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>
 11: #include <petscblaslapack.h>

 13: /* Logging support */
 14: 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;
 15: PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;

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

 30: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

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

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

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

 41:   Level: intermediate

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

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

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

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

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

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

 76:   Level: developer

 78:   Note:
 79:   This function requires that tensor cells are ordered last.

 81: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
 82: @*/
 83: PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
 84: {
 85:   DMLabel         ctLabel;
 86:   IS              valueIS;
 87:   const PetscInt *ctypes;
 88:   PetscInt        Nct, cS = PETSC_MAX_INT, cE = 0;

 90:   PetscFunctionBegin;
 91:   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
 92:   PetscCall(DMLabelGetValueIS(ctLabel, &valueIS));
 93:   PetscCall(ISGetLocalSize(valueIS, &Nct));
 94:   PetscCall(ISGetIndices(valueIS, &ctypes));
 95:   if (!Nct) cS = cE = 0;
 96:   for (PetscInt t = 0; t < Nct; ++t) {
 97:     const DMPolytopeType ct = (DMPolytopeType)ctypes[t];
 98:     PetscInt             ctS, ctE, ht;

100:     if (ct == DM_POLYTOPE_UNKNOWN) {
101:       // If any cells are not typed, just use all cells
102:       PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd));
103:       break;
104:     }
105:     if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue;
106:     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE));
107:     if (ctS >= ctE) continue;
108:     // Check that a point has the right height
109:     PetscCall(DMPlexGetPointHeight(dm, ctS, &ht));
110:     if (ht != height) continue;
111:     cS = PetscMin(cS, ctS);
112:     cE = PetscMax(cE, ctE);
113:   }
114:   PetscCall(ISDestroy(&valueIS));
115:   // Reset label for fast lookup
116:   PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
117:   if (cStart) *cStart = cS;
118:   if (cEnd) *cEnd = cE;
119:   PetscFunctionReturn(PETSC_SUCCESS);
120: }

122: PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft)
123: {
124:   PetscInt                 cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t;
125:   PetscInt                *sStart, *sEnd;
126:   PetscViewerVTKFieldType *ft;
127:   PetscInt                 vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1];
128:   DMLabel                  depthLabel, ctLabel;

130:   PetscFunctionBegin;
131:   /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */
132:   PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1));
133:   PetscCall(DMGetCoordinateDim(dm, &cdim));
134:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
135:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
136:   if (field >= 0) {
137:     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES]));
138:   } else {
139:     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES]));
140:   }

142:   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
143:   PetscCall(DMPlexGetDepth(dm, &depth));
144:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
145:   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
146:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
147:     const DMPolytopeType ict = (DMPolytopeType)c;
148:     PetscInt             dep;

150:     if (ict == DM_POLYTOPE_FV_GHOST) continue;
151:     PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
152:     if (pStart >= 0) {
153:       PetscCall(DMLabelGetValue(depthLabel, cStart, &dep));
154:       if (dep != depth - cellHeight) continue;
155:     }
156:     if (field >= 0) {
157:       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c]));
158:     } else {
159:       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c]));
160:     }
161:   }

163:   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
164:   *types = 0;

166:   for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) {
167:     if (globalvcdof[c]) ++(*types);
168:   }

170:   PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft));
171:   t = 0;
172:   if (globalvcdof[DM_NUM_POLYTOPES]) {
173:     sStart[t] = vStart;
174:     sEnd[t]   = vEnd;
175:     ft[t]     = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
176:     ++t;
177:   }

179:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
180:     if (globalvcdof[c]) {
181:       const DMPolytopeType ict = (DMPolytopeType)c;

183:       PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
184:       sStart[t] = cStart;
185:       sEnd[t]   = cEnd;
186:       ft[t]     = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD;
187:       ++t;
188:     }
189:   }

191:   if (!*types) {
192:     if (field >= 0) {
193:       const char *fieldname;

195:       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
196:       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
197:     } else {
198:       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
199:     }
200:   }

202:   *ssStart = sStart;
203:   *ssEnd   = sEnd;
204:   *sft     = ft;
205:   PetscFunctionReturn(PETSC_SUCCESS);
206: }

208: PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft)
209: {
210:   PetscFunctionBegin;
211:   PetscCall(PetscFree3(*sStart, *sEnd, *ft));
212:   PetscFunctionReturn(PETSC_SUCCESS);
213: }

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

220:   PetscFunctionBegin;
221:   *ft = PETSC_VTK_INVALID;
222:   PetscCall(DMGetCoordinateDim(dm, &cdim));
223:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
224:   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
225:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
226:   if (field >= 0) {
227:     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
228:     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
229:   } else {
230:     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
231:     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
232:   }
233:   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
234:   if (globalvcdof[0]) {
235:     *sStart = vStart;
236:     *sEnd   = vEnd;
237:     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
238:     else *ft = PETSC_VTK_POINT_FIELD;
239:   } else if (globalvcdof[1]) {
240:     *sStart = cStart;
241:     *sEnd   = cEnd;
242:     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
243:     else *ft = PETSC_VTK_CELL_FIELD;
244:   } else {
245:     if (field >= 0) {
246:       const char *fieldname;

248:       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
249:       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
250:     } else {
251:       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
252:     }
253:   }
254:   PetscFunctionReturn(PETSC_SUCCESS);
255: }

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

260:   Collective

262:   Input Parameters:
263: + dm     - The `DMPLEX` object
264: . n      - The number of vectors
265: . u      - The array of local vectors
266: - viewer - The `PetscViewer`

268:   Level: advanced

270: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
271: @*/
272: PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
273: {
274:   PetscDS            ds;
275:   PetscDraw          draw = NULL;
276:   PetscDrawLG        lg;
277:   Vec                coordinates;
278:   const PetscScalar *coords, **sol;
279:   PetscReal         *vals;
280:   PetscInt          *Nc;
281:   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
282:   char             **names;

284:   PetscFunctionBegin;
285:   PetscCall(DMGetDS(dm, &ds));
286:   PetscCall(PetscDSGetNumFields(ds, &Nf));
287:   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
288:   PetscCall(PetscDSGetComponents(ds, &Nc));

290:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
291:   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
292:   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));

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

298:     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
299:     for (f = 0; f < Nf; ++f) {
300:       PetscObject disc;
301:       const char *fname;
302:       char        tmpname[PETSC_MAX_PATH_LEN];

304:       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
305:       /* TODO Create names for components */
306:       for (c = 0; c < Nc[f]; ++c, ++l) {
307:         PetscCall(PetscObjectGetName(disc, &fname));
308:         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
309:         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
310:         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
311:         PetscCall(PetscStrallocpy(tmpname, &names[l]));
312:       }
313:     }
314:   }
315:   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
316:   /* Just add P_1 support for now */
317:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
318:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
319:   PetscCall(VecGetArrayRead(coordinates, &coords));
320:   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
321:   for (v = vStart; v < vEnd; ++v) {
322:     PetscScalar *x, *svals;

324:     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
325:     for (i = 0; i < n; ++i) {
326:       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
327:       for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
328:     }
329:     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
330:   }
331:   PetscCall(VecRestoreArrayRead(coordinates, &coords));
332:   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
333:   for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
334:   PetscCall(PetscFree3(sol, names, vals));

336:   PetscCall(PetscDrawLGDraw(lg));
337:   PetscCall(PetscDrawLGDestroy(&lg));
338:   PetscFunctionReturn(PETSC_SUCCESS);
339: }

341: static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
342: {
343:   DM dm;

345:   PetscFunctionBegin;
346:   PetscCall(VecGetDM(u, &dm));
347:   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
348:   PetscFunctionReturn(PETSC_SUCCESS);
349: }

351: static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
352: {
353:   DM                 dm;
354:   PetscSection       s;
355:   PetscDraw          draw, popup;
356:   DM                 cdm;
357:   PetscSection       coordSection;
358:   Vec                coordinates;
359:   const PetscScalar *array;
360:   PetscReal          lbound[3], ubound[3];
361:   PetscReal          vbound[2], time;
362:   PetscBool          flg;
363:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
364:   const char        *name;
365:   char               title[PETSC_MAX_PATH_LEN];

367:   PetscFunctionBegin;
368:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
369:   PetscCall(VecGetDM(v, &dm));
370:   PetscCall(DMGetCoordinateDim(dm, &dim));
371:   PetscCall(DMGetLocalSection(dm, &s));
372:   PetscCall(PetscSectionGetNumFields(s, &Nf));
373:   PetscCall(DMGetCoarsenLevel(dm, &level));
374:   PetscCall(DMGetCoordinateDM(dm, &cdm));
375:   PetscCall(DMGetLocalSection(cdm, &coordSection));
376:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
377:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
378:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));

380:   PetscCall(PetscObjectGetName((PetscObject)v, &name));
381:   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));

383:   PetscCall(VecGetLocalSize(coordinates, &N));
384:   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
385:   PetscCall(PetscDrawClear(draw));

387:   /* Could implement something like DMDASelectFields() */
388:   for (f = 0; f < Nf; ++f) {
389:     DM          fdm = dm;
390:     Vec         fv  = v;
391:     IS          fis;
392:     char        prefix[PETSC_MAX_PATH_LEN];
393:     const char *fname;

395:     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
396:     PetscCall(PetscSectionGetFieldName(s, f, &fname));

398:     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
399:     else prefix[0] = '\0';
400:     if (Nf > 1) {
401:       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
402:       PetscCall(VecGetSubVector(v, fis, &fv));
403:       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
404:       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
405:     }
406:     for (comp = 0; comp < Nc; ++comp, ++w) {
407:       PetscInt nmax = 2;

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

414:       /* TODO Get max and min only for this component */
415:       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
416:       if (!flg) {
417:         PetscCall(VecMin(fv, NULL, &vbound[0]));
418:         PetscCall(VecMax(fv, NULL, &vbound[1]));
419:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
420:       }

422:       PetscCall(PetscDrawGetPopup(draw, &popup));
423:       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
424:       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
425:       PetscCall(VecGetArrayRead(fv, &array));
426:       for (c = cStart; c < cEnd; ++c) {
427:         PetscScalar       *coords = NULL, *a = NULL;
428:         const PetscScalar *coords_arr;
429:         PetscBool          isDG;
430:         PetscInt           numCoords, color[4] = {-1, -1, -1, -1};

432:         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
433:         if (a) {
434:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
435:           color[1] = color[2] = color[3] = color[0];
436:         } else {
437:           PetscScalar *vals = NULL;
438:           PetscInt     numVals, va;

440:           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
441:           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);
442:           switch (numVals / Nc) {
443:           case 3: /* P1 Triangle */
444:           case 4: /* P1 Quadrangle */
445:             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
446:             break;
447:           case 6: /* P2 Triangle */
448:           case 8: /* P2 Quadrangle */
449:             for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]);
450:             break;
451:           default:
452:             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
453:           }
454:           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
455:         }
456:         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
457:         switch (numCoords) {
458:         case 6:
459:         case 12: /* Localized triangle */
460:           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]));
461:           break;
462:         case 8:
463:         case 16: /* Localized quadrilateral */
464:           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]));
465:           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]));
466:           break;
467:         default:
468:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
469:         }
470:         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
471:       }
472:       PetscCall(VecRestoreArrayRead(fv, &array));
473:       PetscCall(PetscDrawFlush(draw));
474:       PetscCall(PetscDrawPause(draw));
475:       PetscCall(PetscDrawSave(draw));
476:     }
477:     if (Nf > 1) {
478:       PetscCall(VecRestoreSubVector(v, fis, &fv));
479:       PetscCall(ISDestroy(&fis));
480:       PetscCall(DMDestroy(&fdm));
481:     }
482:   }
483:   PetscFunctionReturn(PETSC_SUCCESS);
484: }

486: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
487: {
488:   DM        dm;
489:   PetscDraw draw;
490:   PetscInt  dim;
491:   PetscBool isnull;

493:   PetscFunctionBegin;
494:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
495:   PetscCall(PetscDrawIsNull(draw, &isnull));
496:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);

498:   PetscCall(VecGetDM(v, &dm));
499:   PetscCall(DMGetCoordinateDim(dm, &dim));
500:   switch (dim) {
501:   case 1:
502:     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
503:     break;
504:   case 2:
505:     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
506:     break;
507:   default:
508:     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
509:   }
510:   PetscFunctionReturn(PETSC_SUCCESS);
511: }

513: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
514: {
515:   DM                      dm;
516:   Vec                     locv;
517:   const char             *name;
518:   PetscSection            section;
519:   PetscInt                pStart, pEnd;
520:   PetscInt                numFields;
521:   PetscViewerVTKFieldType ft;

523:   PetscFunctionBegin;
524:   PetscCall(VecGetDM(v, &dm));
525:   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
526:   PetscCall(PetscObjectGetName((PetscObject)v, &name));
527:   PetscCall(PetscObjectSetName((PetscObject)locv, name));
528:   PetscCall(VecCopy(v, locv));
529:   PetscCall(DMGetLocalSection(dm, &section));
530:   PetscCall(PetscSectionGetNumFields(section, &numFields));
531:   if (!numFields) {
532:     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
533:     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
534:   } else {
535:     PetscInt f;

537:     for (f = 0; f < numFields; f++) {
538:       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
539:       if (ft == PETSC_VTK_INVALID) continue;
540:       PetscCall(PetscObjectReference((PetscObject)locv));
541:       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
542:     }
543:     PetscCall(VecDestroy(&locv));
544:   }
545:   PetscFunctionReturn(PETSC_SUCCESS);
546: }

548: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
549: {
550:   DM        dm;
551:   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;

553:   PetscFunctionBegin;
554:   PetscCall(VecGetDM(v, &dm));
555:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
556:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
557:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
558:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
559:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
560:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
561:   if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
562:     PetscInt    i, numFields;
563:     PetscObject fe;
564:     PetscBool   fem  = PETSC_FALSE;
565:     Vec         locv = v;
566:     const char *name;
567:     PetscInt    step;
568:     PetscReal   time;

570:     PetscCall(DMGetNumFields(dm, &numFields));
571:     for (i = 0; i < numFields; i++) {
572:       PetscCall(DMGetField(dm, i, NULL, &fe));
573:       if (fe->classid == PETSCFE_CLASSID) {
574:         fem = PETSC_TRUE;
575:         break;
576:       }
577:     }
578:     if (fem) {
579:       PetscObject isZero;

581:       PetscCall(DMGetLocalVector(dm, &locv));
582:       PetscCall(PetscObjectGetName((PetscObject)v, &name));
583:       PetscCall(PetscObjectSetName((PetscObject)locv, name));
584:       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
585:       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
586:       PetscCall(VecCopy(v, locv));
587:       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
588:       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
589:     }
590:     if (isvtk) {
591:       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
592:     } else if (ishdf5) {
593: #if defined(PETSC_HAVE_HDF5)
594:       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
595: #else
596:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
597: #endif
598:     } else if (isdraw) {
599:       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
600:     } else if (isglvis) {
601:       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
602:       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
603:       PetscCall(VecView_GLVis(locv, viewer));
604:     } else if (iscgns) {
605: #if defined(PETSC_HAVE_CGNS)
606:       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
607: #else
608:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
609: #endif
610:     }
611:     if (fem) {
612:       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
613:       PetscCall(DMRestoreLocalVector(dm, &locv));
614:     }
615:   } else {
616:     PetscBool isseq;

618:     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
619:     if (isseq) PetscCall(VecView_Seq(v, viewer));
620:     else PetscCall(VecView_MPI(v, viewer));
621:   }
622:   PetscFunctionReturn(PETSC_SUCCESS);
623: }

625: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
626: {
627:   DM        dm;
628:   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;

630:   PetscFunctionBegin;
631:   PetscCall(VecGetDM(v, &dm));
632:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
633:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
634:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
635:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
636:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
637:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
638:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
639:   if (isvtk || isdraw || isglvis || iscgns) {
640:     Vec         locv;
641:     PetscObject isZero;
642:     const char *name;

644:     PetscCall(DMGetLocalVector(dm, &locv));
645:     PetscCall(PetscObjectGetName((PetscObject)v, &name));
646:     PetscCall(PetscObjectSetName((PetscObject)locv, name));
647:     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
648:     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
649:     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
650:     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
651:     PetscCall(VecView_Plex_Local(locv, viewer));
652:     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
653:     PetscCall(DMRestoreLocalVector(dm, &locv));
654:   } else if (ishdf5) {
655: #if defined(PETSC_HAVE_HDF5)
656:     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
657: #else
658:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
659: #endif
660:   } else if (isexodusii) {
661: #if defined(PETSC_HAVE_EXODUSII)
662:     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
663: #else
664:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
665: #endif
666:   } else {
667:     PetscBool isseq;

669:     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
670:     if (isseq) PetscCall(VecView_Seq(v, viewer));
671:     else PetscCall(VecView_MPI(v, viewer));
672:   }
673:   PetscFunctionReturn(PETSC_SUCCESS);
674: }

676: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
677: {
678:   DM                dm;
679:   MPI_Comm          comm;
680:   PetscViewerFormat format;
681:   Vec               v;
682:   PetscBool         isvtk, ishdf5;

684:   PetscFunctionBegin;
685:   PetscCall(VecGetDM(originalv, &dm));
686:   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
687:   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
688:   PetscCall(PetscViewerGetFormat(viewer, &format));
689:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
690:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
691:   if (format == PETSC_VIEWER_NATIVE) {
692:     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
693:     /* this need a better fix */
694:     if (dm->useNatural) {
695:       if (dm->sfNatural) {
696:         const char *vecname;
697:         PetscInt    n, nroots;

699:         PetscCall(VecGetLocalSize(originalv, &n));
700:         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
701:         if (n == nroots) {
702:           PetscCall(DMPlexCreateNaturalVector(dm, &v));
703:           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
704:           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
705:           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
706:           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
707:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
708:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
709:     } else v = originalv;
710:   } else v = originalv;

712:   if (ishdf5) {
713: #if defined(PETSC_HAVE_HDF5)
714:     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
715: #else
716:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
717: #endif
718:   } else if (isvtk) {
719:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
720:   } else {
721:     PetscBool isseq;

723:     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
724:     if (isseq) PetscCall(VecView_Seq(v, viewer));
725:     else PetscCall(VecView_MPI(v, viewer));
726:   }
727:   if (v != originalv) PetscCall(VecDestroy(&v));
728:   PetscFunctionReturn(PETSC_SUCCESS);
729: }

731: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
732: {
733:   DM        dm;
734:   PetscBool ishdf5;

736:   PetscFunctionBegin;
737:   PetscCall(VecGetDM(v, &dm));
738:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
739:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
740:   if (ishdf5) {
741:     DM          dmBC;
742:     Vec         gv;
743:     const char *name;

745:     PetscCall(DMGetOutputDM(dm, &dmBC));
746:     PetscCall(DMGetGlobalVector(dmBC, &gv));
747:     PetscCall(PetscObjectGetName((PetscObject)v, &name));
748:     PetscCall(PetscObjectSetName((PetscObject)gv, name));
749:     PetscCall(VecLoad_Default(gv, viewer));
750:     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
751:     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
752:     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
753:   } else PetscCall(VecLoad_Default(v, viewer));
754:   PetscFunctionReturn(PETSC_SUCCESS);
755: }

757: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
758: {
759:   DM        dm;
760:   PetscBool ishdf5, isexodusii;

762:   PetscFunctionBegin;
763:   PetscCall(VecGetDM(v, &dm));
764:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
765:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
766:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
767:   if (ishdf5) {
768: #if defined(PETSC_HAVE_HDF5)
769:     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
770: #else
771:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
772: #endif
773:   } else if (isexodusii) {
774: #if defined(PETSC_HAVE_EXODUSII)
775:     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
776: #else
777:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
778: #endif
779:   } else PetscCall(VecLoad_Default(v, viewer));
780:   PetscFunctionReturn(PETSC_SUCCESS);
781: }

783: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
784: {
785:   DM                dm;
786:   PetscViewerFormat format;
787:   PetscBool         ishdf5;

789:   PetscFunctionBegin;
790:   PetscCall(VecGetDM(originalv, &dm));
791:   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
792:   PetscCall(PetscViewerGetFormat(viewer, &format));
793:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
794:   if (format == PETSC_VIEWER_NATIVE) {
795:     if (dm->useNatural) {
796:       if (dm->sfNatural) {
797:         if (ishdf5) {
798: #if defined(PETSC_HAVE_HDF5)
799:           Vec         v;
800:           const char *vecname;

802:           PetscCall(DMPlexCreateNaturalVector(dm, &v));
803:           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
804:           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
805:           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
806:           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
807:           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
808:           PetscCall(VecDestroy(&v));
809: #else
810:           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
811: #endif
812:         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
813:       }
814:     } else PetscCall(VecLoad_Default(originalv, viewer));
815:   }
816:   PetscFunctionReturn(PETSC_SUCCESS);
817: }

819: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
820: {
821:   PetscSection       coordSection;
822:   Vec                coordinates;
823:   DMLabel            depthLabel, celltypeLabel;
824:   const char        *name[4];
825:   const PetscScalar *a;
826:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;

828:   PetscFunctionBegin;
829:   PetscCall(DMGetDimension(dm, &dim));
830:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
831:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
832:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
833:   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
834:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
835:   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
836:   PetscCall(VecGetArrayRead(coordinates, &a));
837:   name[0]       = "vertex";
838:   name[1]       = "edge";
839:   name[dim - 1] = "face";
840:   name[dim]     = "cell";
841:   for (c = cStart; c < cEnd; ++c) {
842:     PetscInt *closure = NULL;
843:     PetscInt  closureSize, cl, ct;

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

852:       if ((point < pStart) || (point >= pEnd)) continue;
853:       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
854:       if (!dof) continue;
855:       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
856:       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
857:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
858:       for (p = 0; p < dof / dim; ++p) {
859:         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
860:         for (d = 0; d < dim; ++d) {
861:           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
862:           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
863:         }
864:         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
865:       }
866:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
867:     }
868:     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
869:     PetscCall(PetscViewerASCIIPopTab(viewer));
870:   }
871:   PetscCall(VecRestoreArrayRead(coordinates, &a));
872:   PetscFunctionReturn(PETSC_SUCCESS);
873: }

875: typedef enum {
876:   CS_CARTESIAN,
877:   CS_POLAR,
878:   CS_CYLINDRICAL,
879:   CS_SPHERICAL
880: } CoordSystem;
881: const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};

883: static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
884: {
885:   PetscInt i;

887:   PetscFunctionBegin;
888:   if (dim > 3) {
889:     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
890:   } else {
891:     PetscReal coords[3], trcoords[3] = {0., 0., 0.};

893:     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
894:     switch (cs) {
895:     case CS_CARTESIAN:
896:       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
897:       break;
898:     case CS_POLAR:
899:       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
900:       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
901:       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
902:       break;
903:     case CS_CYLINDRICAL:
904:       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
905:       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
906:       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
907:       trcoords[2] = coords[2];
908:       break;
909:     case CS_SPHERICAL:
910:       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
911:       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
912:       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
913:       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
914:       break;
915:     }
916:     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
917:   }
918:   PetscFunctionReturn(PETSC_SUCCESS);
919: }

921: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
922: {
923:   DM_Plex          *mesh = (DM_Plex *)dm->data;
924:   DM                cdm, cdmCell;
925:   PetscSection      coordSection, coordSectionCell;
926:   Vec               coordinates, coordinatesCell;
927:   PetscViewerFormat format;

929:   PetscFunctionBegin;
930:   PetscCall(PetscViewerGetFormat(viewer, &format));
931:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
932:     const char *name;
933:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
934:     PetscInt    pStart, pEnd, p, numLabels, l;
935:     PetscMPIInt rank, size;

937:     PetscCall(DMGetCoordinateDM(dm, &cdm));
938:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
939:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
940:     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
941:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
942:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
943:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
944:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
945:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
946:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
947:     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
948:     PetscCall(DMGetDimension(dm, &dim));
949:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
950:     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
951:     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
952:     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
953:     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
954:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
955:     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
956:     for (p = pStart; p < pEnd; ++p) {
957:       PetscInt dof, off, s;

959:       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
960:       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
961:       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
962:     }
963:     PetscCall(PetscViewerFlush(viewer));
964:     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
965:     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
966:     for (p = pStart; p < pEnd; ++p) {
967:       PetscInt dof, off, c;

969:       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
970:       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
971:       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]));
972:     }
973:     PetscCall(PetscViewerFlush(viewer));
974:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
975:     if (coordSection && coordinates) {
976:       CoordSystem        cs = CS_CARTESIAN;
977:       const PetscScalar *array, *arrayCell = NULL;
978:       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
979:       PetscMPIInt        rank;
980:       const char        *name;

982:       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
983:       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
984:       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
985:       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
986:       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
987:       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
988:       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
989:       pStart = PetscMin(pvStart, pcStart);
990:       pEnd   = PetscMax(pvEnd, pcEnd);
991:       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
992:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
993:       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
994:       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));

996:       PetscCall(VecGetArrayRead(coordinates, &array));
997:       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
998:       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
999:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
1000:       for (p = pStart; p < pEnd; ++p) {
1001:         PetscInt dof, off;

1003:         if (p >= pvStart && p < pvEnd) {
1004:           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
1005:           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
1006:           if (dof) {
1007:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
1008:             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
1009:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1010:           }
1011:         }
1012:         if (cdmCell && p >= pcStart && p < pcEnd) {
1013:           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
1014:           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
1015:           if (dof) {
1016:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
1017:             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
1018:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1019:           }
1020:         }
1021:       }
1022:       PetscCall(PetscViewerFlush(viewer));
1023:       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1024:       PetscCall(VecRestoreArrayRead(coordinates, &array));
1025:       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
1026:     }
1027:     PetscCall(DMGetNumLabels(dm, &numLabels));
1028:     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1029:     for (l = 0; l < numLabels; ++l) {
1030:       DMLabel     label;
1031:       PetscBool   isdepth;
1032:       const char *name;

1034:       PetscCall(DMGetLabelName(dm, l, &name));
1035:       PetscCall(PetscStrcmp(name, "depth", &isdepth));
1036:       if (isdepth) continue;
1037:       PetscCall(DMGetLabel(dm, name, &label));
1038:       PetscCall(DMLabelView(label, viewer));
1039:     }
1040:     if (size > 1) {
1041:       PetscSF sf;

1043:       PetscCall(DMGetPointSF(dm, &sf));
1044:       PetscCall(PetscSFView(sf, viewer));
1045:     }
1046:     if (mesh->periodic.face_sfs)
1047:       for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer));
1048:     PetscCall(PetscViewerFlush(viewer));
1049:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
1050:     const char  *name, *color;
1051:     const char  *defcolors[3]  = {"gray", "orange", "green"};
1052:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
1053:     char         lname[PETSC_MAX_PATH_LEN];
1054:     PetscReal    scale      = 2.0;
1055:     PetscReal    tikzscale  = 1.0;
1056:     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
1057:     double       tcoords[3];
1058:     PetscScalar *coords;
1059:     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
1060:     PetscMPIInt  rank, size;
1061:     char       **names, **colors, **lcolors;
1062:     PetscBool    flg, lflg;
1063:     PetscBT      wp = NULL;
1064:     PetscInt     pEnd, pStart;

1066:     PetscCall(DMGetCoordinateDM(dm, &cdm));
1067:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1068:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1069:     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
1070:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
1071:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
1072:     PetscCall(DMGetDimension(dm, &dim));
1073:     PetscCall(DMPlexGetDepth(dm, &depth));
1074:     PetscCall(DMGetNumLabels(dm, &numLabels));
1075:     numLabels  = PetscMax(numLabels, 10);
1076:     numColors  = 10;
1077:     numLColors = 10;
1078:     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
1079:     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
1080:     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
1081:     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
1082:     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
1083:     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
1084:     n = 4;
1085:     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
1086:     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
1087:     n = 4;
1088:     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
1089:     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
1090:     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
1091:     if (!useLabels) numLabels = 0;
1092:     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
1093:     if (!useColors) {
1094:       numColors = 3;
1095:       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
1096:     }
1097:     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
1098:     if (!useColors) {
1099:       numLColors = 4;
1100:       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
1101:     }
1102:     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1103:     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
1104:     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
1105:     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1106:     if (depth < dim) plotEdges = PETSC_FALSE;
1107:     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));

1109:     /* filter points with labelvalue != labeldefaultvalue */
1110:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1111:     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1112:     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
1113:     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1114:     if (lflg) {
1115:       DMLabel lbl;

1117:       PetscCall(DMGetLabel(dm, lname, &lbl));
1118:       if (lbl) {
1119:         PetscInt val, defval;

1121:         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
1122:         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1123:         for (c = pStart; c < pEnd; c++) {
1124:           PetscInt *closure = NULL;
1125:           PetscInt  closureSize;

1127:           PetscCall(DMLabelGetValue(lbl, c, &val));
1128:           if (val == defval) continue;

1130:           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1131:           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
1132:           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1133:         }
1134:       }
1135:     }

1137:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1138:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1139:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1140:     PetscCall(PetscViewerASCIIPrintf(viewer, "\
1141: \\documentclass[tikz]{standalone}\n\n\
1142: \\usepackage{pgflibraryshapes}\n\
1143: \\usetikzlibrary{backgrounds}\n\
1144: \\usetikzlibrary{arrows}\n\
1145: \\begin{document}\n"));
1146:     if (size > 1) {
1147:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1148:       for (p = 0; p < size; ++p) {
1149:         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
1150:         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1151:       }
1152:       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
1153:     }
1154:     if (drawHasse) {
1155:       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart));

1157:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
1158:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
1159:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
1160:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
1161:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
1162:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
1163:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
1164:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
1165:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
1166:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
1167:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
1168:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1169:     }
1170:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));

1172:     /* Plot vertices */
1173:     PetscCall(VecGetArray(coordinates, &coords));
1174:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1175:     for (v = vStart; v < vEnd; ++v) {
1176:       PetscInt  off, dof, d;
1177:       PetscBool isLabeled = PETSC_FALSE;

1179:       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
1180:       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
1181:       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
1182:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1183:       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
1184:       for (d = 0; d < dof; ++d) {
1185:         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1186:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1187:       }
1188:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
1189:       if (dim == 3) {
1190:         PetscReal tmp = tcoords[1];
1191:         tcoords[1]    = tcoords[2];
1192:         tcoords[2]    = -tmp;
1193:       }
1194:       for (d = 0; d < dof; ++d) {
1195:         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1196:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1197:       }
1198:       if (drawHasse) color = colors[0 % numColors];
1199:       else color = colors[rank % numColors];
1200:       for (l = 0; l < numLabels; ++l) {
1201:         PetscInt val;
1202:         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1203:         if (val >= 0) {
1204:           color     = lcolors[l % numLColors];
1205:           isLabeled = PETSC_TRUE;
1206:           break;
1207:         }
1208:       }
1209:       if (drawNumbers[0]) {
1210:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1211:       } else if (drawColors[0]) {
1212:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
1213:       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1214:     }
1215:     PetscCall(VecRestoreArray(coordinates, &coords));
1216:     PetscCall(PetscViewerFlush(viewer));
1217:     /* Plot edges */
1218:     if (plotEdges) {
1219:       PetscCall(VecGetArray(coordinates, &coords));
1220:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1221:       for (e = eStart; e < eEnd; ++e) {
1222:         const PetscInt *cone;
1223:         PetscInt        coneSize, offA, offB, dof, d;

1225:         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1226:         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
1227:         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
1228:         PetscCall(DMPlexGetCone(dm, e, &cone));
1229:         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
1230:         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
1231:         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
1232:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1233:         for (d = 0; d < dof; ++d) {
1234:           tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1235:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1236:         }
1237:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1238:         if (dim == 3) {
1239:           PetscReal tmp = tcoords[1];
1240:           tcoords[1]    = tcoords[2];
1241:           tcoords[2]    = -tmp;
1242:         }
1243:         for (d = 0; d < dof; ++d) {
1244:           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1245:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1246:         }
1247:         if (drawHasse) color = colors[1 % numColors];
1248:         else color = colors[rank % numColors];
1249:         for (l = 0; l < numLabels; ++l) {
1250:           PetscInt val;
1251:           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1252:           if (val >= 0) {
1253:             color = lcolors[l % numLColors];
1254:             break;
1255:           }
1256:         }
1257:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1258:       }
1259:       PetscCall(VecRestoreArray(coordinates, &coords));
1260:       PetscCall(PetscViewerFlush(viewer));
1261:       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1262:     }
1263:     /* Plot cells */
1264:     if (dim == 3 || !drawNumbers[1]) {
1265:       for (e = eStart; e < eEnd; ++e) {
1266:         const PetscInt *cone;

1268:         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1269:         color = colors[rank % numColors];
1270:         for (l = 0; l < numLabels; ++l) {
1271:           PetscInt val;
1272:           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1273:           if (val >= 0) {
1274:             color = lcolors[l % numLColors];
1275:             break;
1276:           }
1277:         }
1278:         PetscCall(DMPlexGetCone(dm, e, &cone));
1279:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1280:       }
1281:     } else {
1282:       DMPolytopeType ct;

1284:       /* Drawing a 2D polygon */
1285:       for (c = cStart; c < cEnd; ++c) {
1286:         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1287:         PetscCall(DMPlexGetCellType(dm, c, &ct));
1288:         if (DMPolytopeTypeIsHybrid(ct)) {
1289:           const PetscInt *cone;
1290:           PetscInt        coneSize, e;

1292:           PetscCall(DMPlexGetCone(dm, c, &cone));
1293:           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1294:           for (e = 0; e < coneSize; ++e) {
1295:             const PetscInt *econe;

1297:             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
1298:             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));
1299:           }
1300:         } else {
1301:           PetscInt *closure = NULL;
1302:           PetscInt  closureSize, Nv = 0, v;

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

1308:             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1309:           }
1310:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1311:           for (v = 0; v <= Nv; ++v) {
1312:             const PetscInt vertex = closure[v % Nv];

1314:             if (v > 0) {
1315:               if (plotEdges) {
1316:                 const PetscInt *edge;
1317:                 PetscInt        endpoints[2], ne;

1319:                 endpoints[0] = closure[v - 1];
1320:                 endpoints[1] = vertex;
1321:                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
1322:                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
1323:                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
1324:                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
1325:               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1326:             }
1327:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1328:           }
1329:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
1330:           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1331:         }
1332:       }
1333:     }
1334:     for (c = cStart; c < cEnd; ++c) {
1335:       double             ccoords[3] = {0.0, 0.0, 0.0};
1336:       PetscBool          isLabeled  = PETSC_FALSE;
1337:       PetscScalar       *cellCoords = NULL;
1338:       const PetscScalar *array;
1339:       PetscInt           numCoords, cdim, d;
1340:       PetscBool          isDG;

1342:       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1343:       PetscCall(DMGetCoordinateDim(dm, &cdim));
1344:       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1345:       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
1346:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1347:       for (p = 0; p < numCoords / cdim; ++p) {
1348:         for (d = 0; d < cdim; ++d) {
1349:           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1350:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1351:         }
1352:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1353:         if (cdim == 3) {
1354:           PetscReal tmp = tcoords[1];
1355:           tcoords[1]    = tcoords[2];
1356:           tcoords[2]    = -tmp;
1357:         }
1358:         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1359:       }
1360:       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1361:       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1362:       for (d = 0; d < cdim; ++d) {
1363:         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1364:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1365:       }
1366:       if (drawHasse) color = colors[depth % numColors];
1367:       else color = colors[rank % numColors];
1368:       for (l = 0; l < numLabels; ++l) {
1369:         PetscInt val;
1370:         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
1371:         if (val >= 0) {
1372:           color     = lcolors[l % numLColors];
1373:           isLabeled = PETSC_TRUE;
1374:           break;
1375:         }
1376:       }
1377:       if (drawNumbers[dim]) {
1378:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1379:       } else if (drawColors[dim]) {
1380:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
1381:       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1382:     }
1383:     if (drawHasse) {
1384:       color = colors[depth % numColors];
1385:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
1386:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
1387:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1388:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
1389:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1391:       color = colors[1 % numColors];
1392:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
1393:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
1394:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1395:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
1396:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1398:       color = colors[0 % numColors];
1399:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
1400:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
1401:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1402:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
1403:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1405:       for (p = pStart; p < pEnd; ++p) {
1406:         const PetscInt *cone;
1407:         PetscInt        coneSize, cp;

1409:         PetscCall(DMPlexGetCone(dm, p, &cone));
1410:         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1411:         for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1412:       }
1413:     }
1414:     PetscCall(PetscViewerFlush(viewer));
1415:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1416:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
1417:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
1418:     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
1419:     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
1420:     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
1421:     PetscCall(PetscFree3(names, colors, lcolors));
1422:     PetscCall(PetscBTDestroy(&wp));
1423:   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1424:     Vec                    cown, acown;
1425:     VecScatter             sct;
1426:     ISLocalToGlobalMapping g2l;
1427:     IS                     gid, acis;
1428:     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
1429:     MPI_Group              ggroup, ngroup;
1430:     PetscScalar           *array, nid;
1431:     const PetscInt        *idxs;
1432:     PetscInt              *idxs2, *start, *adjacency, *work;
1433:     PetscInt64             lm[3], gm[3];
1434:     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
1435:     PetscMPIInt            d1, d2, rank;

1437:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1438:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1439: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1440:     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
1441: #endif
1442:     if (ncomm != MPI_COMM_NULL) {
1443:       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
1444:       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
1445:       d1 = 0;
1446:       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
1447:       nid = d2;
1448:       PetscCallMPI(MPI_Group_free(&ggroup));
1449:       PetscCallMPI(MPI_Group_free(&ngroup));
1450:       PetscCallMPI(MPI_Comm_free(&ncomm));
1451:     } else nid = 0.0;

1453:     /* Get connectivity */
1454:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1455:     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));

1457:     /* filter overlapped local cells */
1458:     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
1459:     PetscCall(ISGetIndices(gid, &idxs));
1460:     PetscCall(ISGetLocalSize(gid, &cum));
1461:     PetscCall(PetscMalloc1(cum, &idxs2));
1462:     for (c = cStart, cum = 0; c < cEnd; c++) {
1463:       if (idxs[c - cStart] < 0) continue;
1464:       idxs2[cum++] = idxs[c - cStart];
1465:     }
1466:     PetscCall(ISRestoreIndices(gid, &idxs));
1467:     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
1468:     PetscCall(ISDestroy(&gid));
1469:     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));

1471:     /* support for node-aware cell locality */
1472:     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
1473:     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
1474:     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
1475:     PetscCall(VecGetArray(cown, &array));
1476:     for (c = 0; c < numVertices; c++) array[c] = nid;
1477:     PetscCall(VecRestoreArray(cown, &array));
1478:     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
1479:     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1480:     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1481:     PetscCall(ISDestroy(&acis));
1482:     PetscCall(VecScatterDestroy(&sct));
1483:     PetscCall(VecDestroy(&cown));

1485:     /* compute edgeCut */
1486:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
1487:     PetscCall(PetscMalloc1(cum, &work));
1488:     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
1489:     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
1490:     PetscCall(ISDestroy(&gid));
1491:     PetscCall(VecGetArray(acown, &array));
1492:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1493:       PetscInt totl;

1495:       totl = start[c + 1] - start[c];
1496:       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
1497:       for (i = 0; i < totl; i++) {
1498:         if (work[i] < 0) {
1499:           ect += 1;
1500:           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1501:         }
1502:       }
1503:     }
1504:     PetscCall(PetscFree(work));
1505:     PetscCall(VecRestoreArray(acown, &array));
1506:     lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
1507:     lm[1] = -numVertices;
1508:     PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
1509:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0]));
1510:     lm[0] = ect;                     /* edgeCut */
1511:     lm[1] = ectn;                    /* node-aware edgeCut */
1512:     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1513:     PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
1514:     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1515: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1516:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.));
1517: #else
1518:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
1519: #endif
1520:     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
1521:     PetscCall(PetscFree(start));
1522:     PetscCall(PetscFree(adjacency));
1523:     PetscCall(VecDestroy(&acown));
1524:   } else {
1525:     const char    *name;
1526:     PetscInt      *sizes, *hybsizes, *ghostsizes;
1527:     PetscInt       locDepth, depth, cellHeight, dim, d;
1528:     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1529:     PetscInt       numLabels, l, maxSize = 17;
1530:     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1531:     MPI_Comm       comm;
1532:     PetscMPIInt    size, rank;

1534:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1535:     PetscCallMPI(MPI_Comm_size(comm, &size));
1536:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1537:     PetscCall(DMGetDimension(dm, &dim));
1538:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1539:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1540:     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1541:     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
1542:     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
1543:     PetscCall(DMPlexGetDepth(dm, &locDepth));
1544:     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
1545:     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1546:     gcNum = gcEnd - gcStart;
1547:     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
1548:     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1549:     for (d = 0; d <= depth; d++) {
1550:       PetscInt Nc[2] = {0, 0}, ict;

1552:       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1553:       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1554:       ict = ct0;
1555:       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1556:       ct0 = (DMPolytopeType)ict;
1557:       for (p = pStart; p < pEnd; ++p) {
1558:         DMPolytopeType ct;

1560:         PetscCall(DMPlexGetCellType(dm, p, &ct));
1561:         if (ct == ct0) ++Nc[0];
1562:         else ++Nc[1];
1563:       }
1564:       if (size < maxSize) {
1565:         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
1566:         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
1567:         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
1568:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1569:         for (p = 0; p < size; ++p) {
1570:           if (rank == 0) {
1571:             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
1572:             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
1573:             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1574:           }
1575:         }
1576:       } else {
1577:         PetscInt locMinMax[2];

1579:         locMinMax[0] = Nc[0] + Nc[1];
1580:         locMinMax[1] = Nc[0] + Nc[1];
1581:         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1582:         locMinMax[0] = Nc[1];
1583:         locMinMax[1] = Nc[1];
1584:         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1585:         if (d == depth) {
1586:           locMinMax[0] = gcNum;
1587:           locMinMax[1] = gcNum;
1588:           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1589:         }
1590:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1591:         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
1592:         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
1593:         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1594:       }
1595:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1596:     }
1597:     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
1598:     {
1599:       const PetscReal *maxCell;
1600:       const PetscReal *L;
1601:       PetscBool        localized;

1603:       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
1604:       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1605:       if (L || localized) {
1606:         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
1607:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1608:         if (L) {
1609:           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
1610:           for (d = 0; d < dim; ++d) {
1611:             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1612:             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
1613:           }
1614:           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
1615:         }
1616:         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
1617:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1618:       }
1619:     }
1620:     PetscCall(DMGetNumLabels(dm, &numLabels));
1621:     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1622:     for (l = 0; l < numLabels; ++l) {
1623:       DMLabel         label;
1624:       const char     *name;
1625:       IS              valueIS;
1626:       const PetscInt *values;
1627:       PetscInt        numValues, v;

1629:       PetscCall(DMGetLabelName(dm, l, &name));
1630:       PetscCall(DMGetLabel(dm, name, &label));
1631:       PetscCall(DMLabelGetNumValues(label, &numValues));
1632:       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1633:       PetscCall(DMLabelGetValueIS(label, &valueIS));
1634:       PetscCall(ISGetIndices(valueIS, &values));
1635:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1636:       for (v = 0; v < numValues; ++v) {
1637:         PetscInt size;

1639:         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
1640:         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1641:         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1642:       }
1643:       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
1644:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1645:       PetscCall(ISRestoreIndices(valueIS, &values));
1646:       PetscCall(ISDestroy(&valueIS));
1647:     }
1648:     {
1649:       char    **labelNames;
1650:       PetscInt  Nl = numLabels;
1651:       PetscBool flg;

1653:       PetscCall(PetscMalloc1(Nl, &labelNames));
1654:       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1655:       for (l = 0; l < Nl; ++l) {
1656:         DMLabel label;

1658:         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1659:         if (flg) {
1660:           PetscCall(DMGetLabel(dm, labelNames[l], &label));
1661:           PetscCall(DMLabelView(label, viewer));
1662:         }
1663:         PetscCall(PetscFree(labelNames[l]));
1664:       }
1665:       PetscCall(PetscFree(labelNames));
1666:     }
1667:     /* If no fields are specified, people do not want to see adjacency */
1668:     if (dm->Nf) {
1669:       PetscInt f;

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

1674:         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
1675:         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
1676:         PetscCall(PetscViewerASCIIPushTab(viewer));
1677:         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
1678:         if (dm->fields[f].adjacency[0]) {
1679:           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
1680:           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
1681:         } else {
1682:           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
1683:           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
1684:         }
1685:         PetscCall(PetscViewerASCIIPopTab(viewer));
1686:       }
1687:     }
1688:     PetscCall(DMGetCoarseDM(dm, &cdm));
1689:     if (cdm) {
1690:       PetscCall(PetscViewerASCIIPushTab(viewer));
1691:       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
1692:       PetscCall(DMPlexView_Ascii(cdm, viewer));
1693:       PetscCall(PetscViewerASCIIPopTab(viewer));
1694:     }
1695:   }
1696:   PetscFunctionReturn(PETSC_SUCCESS);
1697: }

1699: static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1700: {
1701:   DMPolytopeType ct;
1702:   PetscMPIInt    rank;
1703:   PetscInt       cdim;

1705:   PetscFunctionBegin;
1706:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1707:   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1708:   PetscCall(DMGetCoordinateDim(dm, &cdim));
1709:   switch (ct) {
1710:   case DM_POLYTOPE_SEGMENT:
1711:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1712:     switch (cdim) {
1713:     case 1: {
1714:       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1715:       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */

1717:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
1718:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
1719:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
1720:     } break;
1721:     case 2: {
1722:       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1723:       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1724:       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);

1726:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1727:       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));
1728:       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));
1729:     } break;
1730:     default:
1731:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1732:     }
1733:     break;
1734:   case DM_POLYTOPE_TRIANGLE:
1735:     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));
1736:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1737:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1738:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1739:     break;
1740:   case DM_POLYTOPE_QUADRILATERAL:
1741:     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));
1742:     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));
1743:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1744:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1745:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1746:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1747:     break;
1748:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1749:     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));
1750:     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));
1751:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1752:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1753:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1754:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1755:     break;
1756:   case DM_POLYTOPE_FV_GHOST:
1757:     break;
1758:   default:
1759:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1760:   }
1761:   PetscFunctionReturn(PETSC_SUCCESS);
1762: }

1764: static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1765: {
1766:   PetscReal   centroid[2] = {0., 0.};
1767:   PetscMPIInt rank;
1768:   PetscInt    fillColor;

1770:   PetscFunctionBegin;
1771:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1772:   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1773:   for (PetscInt v = 0; v < Nv; ++v) {
1774:     centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv;
1775:     centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv;
1776:   }
1777:   for (PetscInt e = 0; e < Nv; ++e) {
1778:     refCoords[0] = refVertices[e * 2 + 0];
1779:     refCoords[1] = refVertices[e * 2 + 1];
1780:     for (PetscInt d = 1; d <= edgeDiv; ++d) {
1781:       refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv;
1782:       refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv;
1783:     }
1784:     PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1785:     for (PetscInt d = 0; d < edgeDiv; ++d) {
1786:       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));
1787:       PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK));
1788:     }
1789:   }
1790:   PetscFunctionReturn(PETSC_SUCCESS);
1791: }

1793: static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1794: {
1795:   DMPolytopeType ct;

1797:   PetscFunctionBegin;
1798:   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1799:   switch (ct) {
1800:   case DM_POLYTOPE_TRIANGLE: {
1801:     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};

1803:     PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1804:   } break;
1805:   case DM_POLYTOPE_QUADRILATERAL: {
1806:     PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.};

1808:     PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1809:   } break;
1810:   default:
1811:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1812:   }
1813:   PetscFunctionReturn(PETSC_SUCCESS);
1814: }

1816: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1817: {
1818:   PetscDraw    draw;
1819:   DM           cdm;
1820:   PetscSection coordSection;
1821:   Vec          coordinates;
1822:   PetscReal    xyl[3], xyr[3];
1823:   PetscReal   *refCoords, *edgeCoords;
1824:   PetscBool    isnull, drawAffine;
1825:   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv;

1827:   PetscFunctionBegin;
1828:   PetscCall(DMGetCoordinateDim(dm, &dim));
1829:   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1830:   PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree));
1831:   drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE;
1832:   edgeDiv    = cDegree + 1;
1833:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
1834:   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
1835:   PetscCall(DMGetCoordinateDM(dm, &cdm));
1836:   PetscCall(DMGetLocalSection(cdm, &coordSection));
1837:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1838:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1839:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));

1841:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1842:   PetscCall(PetscDrawIsNull(draw, &isnull));
1843:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
1844:   PetscCall(PetscDrawSetTitle(draw, "Mesh"));

1846:   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
1847:   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
1848:   PetscCall(PetscDrawClear(draw));

1850:   for (c = cStart; c < cEnd; ++c) {
1851:     PetscScalar       *coords = NULL;
1852:     const PetscScalar *coords_arr;
1853:     PetscInt           numCoords;
1854:     PetscBool          isDG;

1856:     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1857:     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
1858:     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1859:     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1860:   }
1861:   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
1862:   PetscCall(PetscDrawFlush(draw));
1863:   PetscCall(PetscDrawPause(draw));
1864:   PetscCall(PetscDrawSave(draw));
1865:   PetscFunctionReturn(PETSC_SUCCESS);
1866: }

1868: static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1869: {
1870:   DM           odm = dm, rdm = dm, cdm;
1871:   PetscFE      fe;
1872:   PetscSpace   sp;
1873:   PetscClassId id;
1874:   PetscInt     degree;
1875:   PetscBool    hoView = PETSC_TRUE;

1877:   PetscFunctionBegin;
1878:   PetscObjectOptionsBegin((PetscObject)dm);
1879:   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
1880:   PetscOptionsEnd();
1881:   PetscCall(PetscObjectReference((PetscObject)dm));
1882:   *hdm = dm;
1883:   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
1884:   PetscCall(DMGetCoordinateDM(dm, &cdm));
1885:   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
1886:   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
1887:   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
1888:   PetscCall(PetscFEGetBasisSpace(fe, &sp));
1889:   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
1890:   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
1891:     DM  cdm, rcdm;
1892:     Mat In;
1893:     Vec cl, rcl;

1895:     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
1896:     PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL));
1897:     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
1898:     PetscCall(DMGetCoordinateDM(odm, &cdm));
1899:     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
1900:     PetscCall(DMGetCoordinatesLocal(odm, &cl));
1901:     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
1902:     PetscCall(DMSetCoarseDM(rcdm, cdm));
1903:     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
1904:     PetscCall(MatMult(In, cl, rcl));
1905:     PetscCall(MatDestroy(&In));
1906:     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
1907:     PetscCall(DMDestroy(&odm));
1908:     odm = rdm;
1909:   }
1910:   *hdm = rdm;
1911:   PetscFunctionReturn(PETSC_SUCCESS);
1912: }

1914: #if defined(PETSC_HAVE_EXODUSII)
1915:   #include <exodusII.h>
1916: #include <petscviewerexodusii.h>
1917: #endif

1919: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1920: {
1921:   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1922:   char      name[PETSC_MAX_PATH_LEN];

1924:   PetscFunctionBegin;
1927:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1928:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
1929:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1930:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1931:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
1932:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
1933:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1934:   if (iascii) {
1935:     PetscViewerFormat format;
1936:     PetscCall(PetscViewerGetFormat(viewer, &format));
1937:     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
1938:     else PetscCall(DMPlexView_Ascii(dm, viewer));
1939:   } else if (ishdf5) {
1940: #if defined(PETSC_HAVE_HDF5)
1941:     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1942: #else
1943:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1944: #endif
1945:   } else if (isvtk) {
1946:     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1947:   } else if (isdraw) {
1948:     DM hdm;

1950:     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
1951:     PetscCall(DMPlexView_Draw(hdm, viewer));
1952:     PetscCall(DMDestroy(&hdm));
1953:   } else if (isglvis) {
1954:     PetscCall(DMPlexView_GLVis(dm, viewer));
1955: #if defined(PETSC_HAVE_EXODUSII)
1956:   } else if (isexodus) {
1957:     /*
1958:       exodusII requires that all sets be part of exactly one cell set.
1959:       If the dm does not have a "Cell Sets" label defined, we create one
1960:       with ID 1, containing all cells.
1961:       Note that if the Cell Sets label is defined but does not cover all cells,
1962:       we may still have a problem. This should probably be checked here or in the viewer;
1963:     */
1964:     PetscInt numCS;
1965:     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
1966:     if (!numCS) {
1967:       PetscInt cStart, cEnd, c;
1968:       PetscCall(DMCreateLabel(dm, "Cell Sets"));
1969:       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1970:       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
1971:     }
1972:     PetscCall(DMView_PlexExodusII(dm, viewer));
1973: #endif
1974: #if defined(PETSC_HAVE_CGNS)
1975:   } else if (iscgns) {
1976:     PetscCall(DMView_PlexCGNS(dm, viewer));
1977: #endif
1978:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1979:   /* Optionally view the partition */
1980:   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1981:   if (flg) {
1982:     Vec ranks;
1983:     PetscCall(DMPlexCreateRankField(dm, &ranks));
1984:     PetscCall(VecView(ranks, viewer));
1985:     PetscCall(VecDestroy(&ranks));
1986:   }
1987:   /* Optionally view a label */
1988:   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1989:   if (flg) {
1990:     DMLabel label;
1991:     Vec     val;

1993:     PetscCall(DMGetLabel(dm, name, &label));
1994:     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1995:     PetscCall(DMPlexCreateLabelField(dm, label, &val));
1996:     PetscCall(VecView(val, viewer));
1997:     PetscCall(VecDestroy(&val));
1998:   }
1999:   PetscFunctionReturn(PETSC_SUCCESS);
2000: }

2002: /*@
2003:   DMPlexTopologyView - Saves a `DMPLEX` topology into a file

2005:   Collective

2007:   Input Parameters:
2008: + dm     - The `DM` whose topology is to be saved
2009: - viewer - The `PetscViewer` to save it in

2011:   Level: advanced

2013: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
2014: @*/
2015: PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2016: {
2017:   PetscBool ishdf5;

2019:   PetscFunctionBegin;
2022:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2023:   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
2024:   if (ishdf5) {
2025: #if defined(PETSC_HAVE_HDF5)
2026:     PetscViewerFormat format;
2027:     PetscCall(PetscViewerGetFormat(viewer, &format));
2028:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2029:       IS globalPointNumbering;

2031:       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
2032:       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
2033:       PetscCall(ISDestroy(&globalPointNumbering));
2034:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
2035: #else
2036:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2037: #endif
2038:   }
2039:   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
2040:   PetscFunctionReturn(PETSC_SUCCESS);
2041: }

2043: /*@
2044:   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file

2046:   Collective

2048:   Input Parameters:
2049: + dm     - The `DM` whose coordinates are to be saved
2050: - viewer - The `PetscViewer` for saving

2052:   Level: advanced

2054: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
2055: @*/
2056: PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2057: {
2058:   PetscBool ishdf5;

2060:   PetscFunctionBegin;
2063:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2064:   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
2065:   if (ishdf5) {
2066: #if defined(PETSC_HAVE_HDF5)
2067:     PetscViewerFormat format;
2068:     PetscCall(PetscViewerGetFormat(viewer, &format));
2069:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2070:       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
2071:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
2072: #else
2073:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2074: #endif
2075:   }
2076:   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
2077:   PetscFunctionReturn(PETSC_SUCCESS);
2078: }

2080: /*@
2081:   DMPlexLabelsView - Saves `DMPLEX` labels into a file

2083:   Collective

2085:   Input Parameters:
2086: + dm     - The `DM` whose labels are to be saved
2087: - viewer - The `PetscViewer` for saving

2089:   Level: advanced

2091: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2092: @*/
2093: PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2094: {
2095:   PetscBool ishdf5;

2097:   PetscFunctionBegin;
2100:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2101:   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2102:   if (ishdf5) {
2103: #if defined(PETSC_HAVE_HDF5)
2104:     IS                globalPointNumbering;
2105:     PetscViewerFormat format;

2107:     PetscCall(PetscViewerGetFormat(viewer, &format));
2108:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2109:       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
2110:       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
2111:       PetscCall(ISDestroy(&globalPointNumbering));
2112:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2113: #else
2114:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2115: #endif
2116:   }
2117:   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
2118:   PetscFunctionReturn(PETSC_SUCCESS);
2119: }

2121: /*@
2122:   DMPlexSectionView - Saves a section associated with a `DMPLEX`

2124:   Collective

2126:   Input Parameters:
2127: + dm        - The `DM` that contains the topology on which the section to be saved is defined
2128: . viewer    - The `PetscViewer` for saving
2129: - sectiondm - The `DM` that contains the section to be saved, can be `NULL`

2131:   Level: advanced

2133:   Notes:
2134:   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.

2136:   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 (or in case `sectiondm` is `NULL`) 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.

2138: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2139: @*/
2140: PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2141: {
2142:   PetscBool ishdf5;

2144:   PetscFunctionBegin;
2147:   if (!sectiondm) sectiondm = dm;
2149:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2150:   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2151:   if (ishdf5) {
2152: #if defined(PETSC_HAVE_HDF5)
2153:     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2154: #else
2155:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2156: #endif
2157:   }
2158:   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
2159:   PetscFunctionReturn(PETSC_SUCCESS);
2160: }

2162: /*@
2163:   DMPlexGlobalVectorView - Saves a global vector

2165:   Collective

2167:   Input Parameters:
2168: + dm        - The `DM` that represents the topology
2169: . viewer    - The `PetscViewer` to save data with
2170: . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2171: - vec       - The global vector to be saved

2173:   Level: advanced

2175:   Notes:
2176:   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 (or in case `sectiondm` is `NULL`) 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.

2178:   Calling sequence:
2179: .vb
2180:        DMCreate(PETSC_COMM_WORLD, &dm);
2181:        DMSetType(dm, DMPLEX);
2182:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2183:        DMClone(dm, &sectiondm);
2184:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2185:        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2186:        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2187:        PetscSectionSetChart(section, pStart, pEnd);
2188:        PetscSectionSetUp(section);
2189:        DMSetLocalSection(sectiondm, section);
2190:        PetscSectionDestroy(&section);
2191:        DMGetGlobalVector(sectiondm, &vec);
2192:        PetscObjectSetName((PetscObject)vec, "vec_name");
2193:        DMPlexTopologyView(dm, viewer);
2194:        DMPlexSectionView(dm, viewer, sectiondm);
2195:        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2196:        DMRestoreGlobalVector(sectiondm, &vec);
2197:        DMDestroy(&sectiondm);
2198:        DMDestroy(&dm);
2199: .ve

2201: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2202: @*/
2203: PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2204: {
2205:   PetscBool ishdf5;

2207:   PetscFunctionBegin;
2210:   if (!sectiondm) sectiondm = dm;
2213:   /* Check consistency */
2214:   {
2215:     PetscSection section;
2216:     PetscBool    includesConstraints;
2217:     PetscInt     m, m1;

2219:     PetscCall(VecGetLocalSize(vec, &m1));
2220:     PetscCall(DMGetGlobalSection(sectiondm, &section));
2221:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2222:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2223:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2224:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2225:   }
2226:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2227:   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2228:   if (ishdf5) {
2229: #if defined(PETSC_HAVE_HDF5)
2230:     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2231: #else
2232:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2233: #endif
2234:   }
2235:   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2236:   PetscFunctionReturn(PETSC_SUCCESS);
2237: }

2239: /*@
2240:   DMPlexLocalVectorView - Saves a local vector

2242:   Collective

2244:   Input Parameters:
2245: + dm        - The `DM` that represents the topology
2246: . viewer    - The `PetscViewer` to save data with
2247: . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL`
2248: - vec       - The local vector to be saved

2250:   Level: advanced

2252:   Note:
2253:   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 (or in case `sectiondm` is `NULL`) 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.

2255:   Calling sequence:
2256: .vb
2257:        DMCreate(PETSC_COMM_WORLD, &dm);
2258:        DMSetType(dm, DMPLEX);
2259:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2260:        DMClone(dm, &sectiondm);
2261:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2262:        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2263:        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2264:        PetscSectionSetChart(section, pStart, pEnd);
2265:        PetscSectionSetUp(section);
2266:        DMSetLocalSection(sectiondm, section);
2267:        DMGetLocalVector(sectiondm, &vec);
2268:        PetscObjectSetName((PetscObject)vec, "vec_name");
2269:        DMPlexTopologyView(dm, viewer);
2270:        DMPlexSectionView(dm, viewer, sectiondm);
2271:        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2272:        DMRestoreLocalVector(sectiondm, &vec);
2273:        DMDestroy(&sectiondm);
2274:        DMDestroy(&dm);
2275: .ve

2277: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2278: @*/
2279: PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2280: {
2281:   PetscBool ishdf5;

2283:   PetscFunctionBegin;
2286:   if (!sectiondm) sectiondm = dm;
2289:   /* Check consistency */
2290:   {
2291:     PetscSection section;
2292:     PetscBool    includesConstraints;
2293:     PetscInt     m, m1;

2295:     PetscCall(VecGetLocalSize(vec, &m1));
2296:     PetscCall(DMGetLocalSection(sectiondm, &section));
2297:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2298:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2299:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2300:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2301:   }
2302:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2303:   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2304:   if (ishdf5) {
2305: #if defined(PETSC_HAVE_HDF5)
2306:     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2307: #else
2308:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2309: #endif
2310:   }
2311:   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2312:   PetscFunctionReturn(PETSC_SUCCESS);
2313: }

2315: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2316: {
2317:   PetscBool ishdf5;

2319:   PetscFunctionBegin;
2322:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2323:   if (ishdf5) {
2324: #if defined(PETSC_HAVE_HDF5)
2325:     PetscViewerFormat format;
2326:     PetscCall(PetscViewerGetFormat(viewer, &format));
2327:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2328:       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2329:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2330:       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
2331:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2332:     PetscFunctionReturn(PETSC_SUCCESS);
2333: #else
2334:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2335: #endif
2336:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2337: }

2339: /*@
2340:   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`

2342:   Collective

2344:   Input Parameters:
2345: + dm     - The `DM` into which the topology is loaded
2346: - viewer - The `PetscViewer` for the saved topology

2348:   Output Parameter:
2349: . 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

2351:   Level: advanced

2353: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2354:           `PetscViewer`, `PetscSF`
2355: @*/
2356: PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2357: {
2358:   PetscBool ishdf5;

2360:   PetscFunctionBegin;
2363:   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
2364:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2365:   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2366:   if (ishdf5) {
2367: #if defined(PETSC_HAVE_HDF5)
2368:     PetscViewerFormat format;
2369:     PetscCall(PetscViewerGetFormat(viewer, &format));
2370:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2371:       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2372:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2373: #else
2374:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2375: #endif
2376:   }
2377:   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2378:   PetscFunctionReturn(PETSC_SUCCESS);
2379: }

2381: /*@
2382:   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`

2384:   Collective

2386:   Input Parameters:
2387: + dm                   - The `DM` into which the coordinates are loaded
2388: . viewer               - The `PetscViewer` for the saved coordinates
2389: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer

2391:   Level: advanced

2393: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2394:           `PetscSF`, `PetscViewer`
2395: @*/
2396: PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2397: {
2398:   PetscBool ishdf5;

2400:   PetscFunctionBegin;
2404:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2405:   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2406:   if (ishdf5) {
2407: #if defined(PETSC_HAVE_HDF5)
2408:     PetscViewerFormat format;
2409:     PetscCall(PetscViewerGetFormat(viewer, &format));
2410:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2411:       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2412:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2413: #else
2414:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2415: #endif
2416:   }
2417:   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2418:   PetscFunctionReturn(PETSC_SUCCESS);
2419: }

2421: /*@
2422:   DMPlexLabelsLoad - Loads labels into a `DMPLEX`

2424:   Collective

2426:   Input Parameters:
2427: + dm                   - The `DM` into which the labels are loaded
2428: . viewer               - The `PetscViewer` for the saved labels
2429: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer

2431:   Level: advanced

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

2436: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2437:           `PetscSF`, `PetscViewer`
2438: @*/
2439: PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2440: {
2441:   PetscBool ishdf5;

2443:   PetscFunctionBegin;
2447:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2448:   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2449:   if (ishdf5) {
2450: #if defined(PETSC_HAVE_HDF5)
2451:     PetscViewerFormat format;

2453:     PetscCall(PetscViewerGetFormat(viewer, &format));
2454:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2455:       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2456:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2457: #else
2458:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2459: #endif
2460:   }
2461:   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2462:   PetscFunctionReturn(PETSC_SUCCESS);
2463: }

2465: /*@
2466:   DMPlexSectionLoad - Loads section into a `DMPLEX`

2468:   Collective

2470:   Input Parameters:
2471: + dm                   - The `DM` that represents the topology
2472: . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
2473: . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL`
2474: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer

2476:   Output Parameters:
2477: + 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)
2478: - 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)

2480:   Level: advanced

2482:   Notes:
2483:   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.

2485:   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 (or in case `sectiondm` is `NULL`) 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.

2487:   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.

2489:   Example using 2 processes:
2490: .vb
2491:   NX (number of points on dm): 4
2492:   sectionA                   : the on-disk section
2493:   vecA                       : a vector associated with sectionA
2494:   sectionB                   : sectiondm's local section constructed in this function
2495:   vecB (local)               : a vector associated with sectiondm's local section
2496:   vecB (global)              : a vector associated with sectiondm's global section

2498:                                      rank 0    rank 1
2499:   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2500:   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2501:   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2502:   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2503:   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2504:   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2505:   sectionB->atlasDof             :     1 0 1 | 1 3
2506:   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2507:   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2508:   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2509: .ve
2510:   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.

2512: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2513: @*/
2514: PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2515: {
2516:   PetscBool ishdf5;

2518:   PetscFunctionBegin;
2521:   if (!sectiondm) sectiondm = dm;
2524:   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
2525:   if (localDofSF) PetscAssertPointer(localDofSF, 6);
2526:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2527:   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2528:   if (ishdf5) {
2529: #if defined(PETSC_HAVE_HDF5)
2530:     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2531: #else
2532:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2533: #endif
2534:   }
2535:   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2536:   PetscFunctionReturn(PETSC_SUCCESS);
2537: }

2539: /*@
2540:   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector

2542:   Collective

2544:   Input Parameters:
2545: + dm        - The `DM` that represents the topology
2546: . viewer    - The `PetscViewer` that represents the on-disk vector data
2547: . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2548: . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2549: - vec       - The global vector to set values of

2551:   Level: advanced

2553:   Notes:
2554:   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 (or in case `sectiondm` is `NULL`) 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.

2556:   Calling sequence:
2557: .vb
2558:        DMCreate(PETSC_COMM_WORLD, &dm);
2559:        DMSetType(dm, DMPLEX);
2560:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2561:        DMPlexTopologyLoad(dm, viewer, &sfX);
2562:        DMClone(dm, &sectiondm);
2563:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2564:        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2565:        DMGetGlobalVector(sectiondm, &vec);
2566:        PetscObjectSetName((PetscObject)vec, "vec_name");
2567:        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2568:        DMRestoreGlobalVector(sectiondm, &vec);
2569:        PetscSFDestroy(&gsf);
2570:        PetscSFDestroy(&sfX);
2571:        DMDestroy(&sectiondm);
2572:        DMDestroy(&dm);
2573: .ve

2575: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2576:           `PetscSF`, `PetscViewer`
2577: @*/
2578: PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2579: {
2580:   PetscBool ishdf5;

2582:   PetscFunctionBegin;
2585:   if (!sectiondm) sectiondm = dm;
2589:   /* Check consistency */
2590:   {
2591:     PetscSection section;
2592:     PetscBool    includesConstraints;
2593:     PetscInt     m, m1;

2595:     PetscCall(VecGetLocalSize(vec, &m1));
2596:     PetscCall(DMGetGlobalSection(sectiondm, &section));
2597:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2598:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2599:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2600:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2601:   }
2602:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2603:   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2604:   if (ishdf5) {
2605: #if defined(PETSC_HAVE_HDF5)
2606:     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2607: #else
2608:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2609: #endif
2610:   }
2611:   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2612:   PetscFunctionReturn(PETSC_SUCCESS);
2613: }

2615: /*@
2616:   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector

2618:   Collective

2620:   Input Parameters:
2621: + dm        - The `DM` that represents the topology
2622: . viewer    - The `PetscViewer` that represents the on-disk vector data
2623: . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL`
2624: . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2625: - vec       - The local vector to set values of

2627:   Level: advanced

2629:   Notes:
2630:   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 (or in case `sectiondm` is `NULL`) 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.

2632:   Calling sequence:
2633: .vb
2634:        DMCreate(PETSC_COMM_WORLD, &dm);
2635:        DMSetType(dm, DMPLEX);
2636:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2637:        DMPlexTopologyLoad(dm, viewer, &sfX);
2638:        DMClone(dm, &sectiondm);
2639:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2640:        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2641:        DMGetLocalVector(sectiondm, &vec);
2642:        PetscObjectSetName((PetscObject)vec, "vec_name");
2643:        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2644:        DMRestoreLocalVector(sectiondm, &vec);
2645:        PetscSFDestroy(&lsf);
2646:        PetscSFDestroy(&sfX);
2647:        DMDestroy(&sectiondm);
2648:        DMDestroy(&dm);
2649: .ve

2651: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2652:           `PetscSF`, `PetscViewer`
2653: @*/
2654: PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2655: {
2656:   PetscBool ishdf5;

2658:   PetscFunctionBegin;
2661:   if (!sectiondm) sectiondm = dm;
2665:   /* Check consistency */
2666:   {
2667:     PetscSection section;
2668:     PetscBool    includesConstraints;
2669:     PetscInt     m, m1;

2671:     PetscCall(VecGetLocalSize(vec, &m1));
2672:     PetscCall(DMGetLocalSection(sectiondm, &section));
2673:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2674:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2675:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2676:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2677:   }
2678:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2679:   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2680:   if (ishdf5) {
2681: #if defined(PETSC_HAVE_HDF5)
2682:     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2683: #else
2684:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2685: #endif
2686:   }
2687:   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2688:   PetscFunctionReturn(PETSC_SUCCESS);
2689: }

2691: PetscErrorCode DMDestroy_Plex(DM dm)
2692: {
2693:   DM_Plex *mesh = (DM_Plex *)dm->data;

2695:   PetscFunctionBegin;
2696:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
2697:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
2698:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
2699:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
2700:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
2701:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2702:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
2703:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
2704:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
2705:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
2706:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2707:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL));
2708:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL));
2709:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL));
2710:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL));
2711:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2712:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2713:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2714:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
2715:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
2716:   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
2717:   PetscCall(PetscSectionDestroy(&mesh->coneSection));
2718:   PetscCall(PetscFree(mesh->cones));
2719:   PetscCall(PetscFree(mesh->coneOrientations));
2720:   PetscCall(PetscSectionDestroy(&mesh->supportSection));
2721:   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
2722:   PetscCall(PetscFree(mesh->supports));
2723:   PetscCall(PetscFree(mesh->cellTypes));
2724:   PetscCall(DMPlexTransformDestroy(&mesh->tr));
2725:   PetscCall(PetscFree(mesh->tetgenOpts));
2726:   PetscCall(PetscFree(mesh->triangleOpts));
2727:   PetscCall(PetscFree(mesh->transformType));
2728:   PetscCall(PetscFree(mesh->distributionName));
2729:   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
2730:   PetscCall(DMLabelDestroy(&mesh->subpointMap));
2731:   PetscCall(ISDestroy(&mesh->subpointIS));
2732:   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
2733:   PetscCall(ISDestroy(&mesh->globalCellNumbers));
2734:   if (mesh->periodic.face_sfs) {
2735:     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i]));
2736:     PetscCall(PetscFree(mesh->periodic.face_sfs));
2737:   }
2738:   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2739:   if (mesh->periodic.periodic_points) {
2740:     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i]));
2741:     PetscCall(PetscFree(mesh->periodic.periodic_points));
2742:   }
2743:   if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform));
2744:   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
2745:   PetscCall(ISDestroy(&mesh->anchorIS));
2746:   PetscCall(PetscSectionDestroy(&mesh->parentSection));
2747:   PetscCall(PetscFree(mesh->parents));
2748:   PetscCall(PetscFree(mesh->childIDs));
2749:   PetscCall(PetscSectionDestroy(&mesh->childSection));
2750:   PetscCall(PetscFree(mesh->children));
2751:   PetscCall(DMDestroy(&mesh->referenceTree));
2752:   PetscCall(PetscGridHashDestroy(&mesh->lbox));
2753:   PetscCall(PetscFree(mesh->neighbors));
2754:   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2755:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2756:   PetscCall(PetscFree(mesh));
2757:   PetscFunctionReturn(PETSC_SUCCESS);
2758: }

2760: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2761: {
2762:   PetscSection           sectionGlobal, sectionLocal;
2763:   PetscInt               bs = -1, mbs;
2764:   PetscInt               localSize, localStart = 0;
2765:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2766:   MatType                mtype;
2767:   ISLocalToGlobalMapping ltog;

2769:   PetscFunctionBegin;
2770:   PetscCall(MatInitializePackage());
2771:   mtype = dm->mattype;
2772:   PetscCall(DMGetLocalSection(dm, &sectionLocal));
2773:   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
2774:   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
2775:   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2776:   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
2777:   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
2778:   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
2779:   PetscCall(MatSetType(*J, mtype));
2780:   PetscCall(MatSetFromOptions(*J));
2781:   PetscCall(MatGetBlockSize(*J, &mbs));
2782:   if (mbs > 1) bs = mbs;
2783:   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
2784:   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
2785:   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
2786:   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
2787:   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
2788:   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
2789:   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
2790:   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2791:   if (!isShell) {
2792:     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2793:     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2794:     PetscInt  pStart, pEnd, p, dof, cdof, num_fields;

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

2798:     PetscCall(PetscCalloc1(localSize, &pblocks));
2799:     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2800:     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2801:     for (p = pStart; p < pEnd; ++p) {
2802:       switch (dm->blocking_type) {
2803:       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
2804:         PetscInt bdof, offset;

2806:         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
2807:         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
2808:         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2809:         if (dof > 0) {
2810:           for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof;
2811:           // Signal block concatenation
2812:           if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof);
2813:         }
2814:         dof  = dof < 0 ? -(dof + 1) : dof;
2815:         bdof = cdof && (dof - cdof) ? 1 : dof;
2816:         if (dof) {
2817:           if (bs < 0) {
2818:             bs = bdof;
2819:           } else if (bs != bdof) {
2820:             bs = 1;
2821:           }
2822:         }
2823:       } break;
2824:       case DM_BLOCKING_FIELD_NODE: {
2825:         for (PetscInt field = 0; field < num_fields; field++) {
2826:           PetscInt num_comp, bdof, offset;
2827:           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2828:           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2829:           if (dof < 0) continue;
2830:           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2831:           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2832:           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);
2833:           PetscInt num_nodes = dof / num_comp;
2834:           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2835:           // Handle possibly constant block size (unlikely)
2836:           bdof = cdof && (dof - cdof) ? 1 : dof;
2837:           if (dof) {
2838:             if (bs < 0) {
2839:               bs = bdof;
2840:             } else if (bs != bdof) {
2841:               bs = 1;
2842:             }
2843:           }
2844:         }
2845:       } break;
2846:       }
2847:     }
2848:     /* Must have same blocksize on all procs (some might have no points) */
2849:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2850:     bsLocal[1] = bs;
2851:     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2852:     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2853:     else bs = bsMinMax[0];
2854:     bs = PetscMax(1, bs);
2855:     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
2856:     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
2857:       PetscCall(MatSetBlockSize(*J, bs));
2858:       PetscCall(MatSetUp(*J));
2859:     } else {
2860:       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
2861:       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
2862:       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2863:     }
2864:     if (pblocks) { // Consolidate blocks
2865:       PetscInt nblocks = 0;
2866:       pblocks[0]       = PetscAbs(pblocks[0]);
2867:       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
2868:         if (pblocks[i] == 0) continue;
2869:         // Negative block size indicates the blocks should be concatenated
2870:         if (pblocks[i] < 0) {
2871:           pblocks[i] = -pblocks[i];
2872:           pblocks[nblocks - 1] += pblocks[i];
2873:         } else {
2874:           pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2875:         }
2876:         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]);
2877:       }
2878:       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
2879:     }
2880:     PetscCall(PetscFree(pblocks));
2881:   }
2882:   PetscCall(MatSetDM(*J, dm));
2883:   PetscFunctionReturn(PETSC_SUCCESS);
2884: }

2886: /*@
2887:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

2889:   Not Collective

2891:   Input Parameter:
2892: . dm - The `DMPLEX`

2894:   Output Parameter:
2895: . subsection - The subdomain section

2897:   Level: developer

2899: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
2900: @*/
2901: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2902: {
2903:   DM_Plex *mesh = (DM_Plex *)dm->data;

2905:   PetscFunctionBegin;
2907:   if (!mesh->subdomainSection) {
2908:     PetscSection section;
2909:     PetscSF      sf;

2911:     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
2912:     PetscCall(DMGetLocalSection(dm, &section));
2913:     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
2914:     PetscCall(PetscSFDestroy(&sf));
2915:   }
2916:   *subsection = mesh->subdomainSection;
2917:   PetscFunctionReturn(PETSC_SUCCESS);
2918: }

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

2923:   Not Collective

2925:   Input Parameter:
2926: . dm - The `DMPLEX`

2928:   Output Parameters:
2929: + pStart - The first mesh point
2930: - pEnd   - The upper bound for mesh points

2932:   Level: beginner

2934: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2935: @*/
2936: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2937: {
2938:   DM_Plex *mesh = (DM_Plex *)dm->data;

2940:   PetscFunctionBegin;
2942:   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
2943:   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2944:   PetscFunctionReturn(PETSC_SUCCESS);
2945: }

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

2950:   Not Collective

2952:   Input Parameters:
2953: + dm     - The `DMPLEX`
2954: . pStart - The first mesh point
2955: - pEnd   - The upper bound for mesh points

2957:   Level: beginner

2959: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2960: @*/
2961: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2962: {
2963:   DM_Plex *mesh = (DM_Plex *)dm->data;

2965:   PetscFunctionBegin;
2967:   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
2968:   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2969:   PetscCall(PetscFree(mesh->cellTypes));
2970:   PetscFunctionReturn(PETSC_SUCCESS);
2971: }

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

2976:   Not Collective

2978:   Input Parameters:
2979: + dm - The `DMPLEX`
2980: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

2982:   Output Parameter:
2983: . size - The cone size for point `p`

2985:   Level: beginner

2987: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2988: @*/
2989: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2990: {
2991:   DM_Plex *mesh = (DM_Plex *)dm->data;

2993:   PetscFunctionBegin;
2995:   PetscAssertPointer(size, 3);
2996:   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
2997:   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
2998:   PetscFunctionReturn(PETSC_SUCCESS);
2999: }

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

3004:   Not Collective

3006:   Input Parameters:
3007: + dm   - The `DMPLEX`
3008: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3009: - size - The cone size for point `p`

3011:   Level: beginner

3013:   Note:
3014:   This should be called after `DMPlexSetChart()`.

3016: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
3017: @*/
3018: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
3019: {
3020:   DM_Plex *mesh = (DM_Plex *)dm->data;

3022:   PetscFunctionBegin;
3024:   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
3025:   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
3026:   PetscFunctionReturn(PETSC_SUCCESS);
3027: }

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

3032:   Not Collective

3034:   Input Parameters:
3035: + dm - The `DMPLEX`
3036: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

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

3041:   Level: beginner

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

3047: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3048: @*/
3049: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3050: {
3051:   DM_Plex *mesh = (DM_Plex *)dm->data;
3052:   PetscInt off;

3054:   PetscFunctionBegin;
3056:   PetscAssertPointer(cone, 3);
3057:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3058:   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
3059:   PetscFunctionReturn(PETSC_SUCCESS);
3060: }

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

3065:   Not Collective

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

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

3075:   Level: intermediate

3077: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
3078: @*/
3079: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
3080: {
3081:   PetscSection cs, newcs;
3082:   PetscInt    *cones;
3083:   PetscInt    *newarr = NULL;
3084:   PetscInt     n;

3086:   PetscFunctionBegin;
3087:   PetscCall(DMPlexGetCones(dm, &cones));
3088:   PetscCall(DMPlexGetConeSection(dm, &cs));
3089:   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
3090:   if (pConesSection) *pConesSection = newcs;
3091:   if (pCones) {
3092:     PetscCall(PetscSectionGetStorageSize(newcs, &n));
3093:     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
3094:   }
3095:   PetscFunctionReturn(PETSC_SUCCESS);
3096: }

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

3101:   Not Collective

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

3107:   Output Parameter:
3108: . expandedPoints - An array of vertices recursively expanded from input points

3110:   Level: advanced

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

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

3117: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3118:           `DMPlexGetDepth()`, `IS`
3119: @*/
3120: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3121: {
3122:   IS      *expandedPointsAll;
3123:   PetscInt depth;

3125:   PetscFunctionBegin;
3128:   PetscAssertPointer(expandedPoints, 3);
3129:   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3130:   *expandedPoints = expandedPointsAll[0];
3131:   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
3132:   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3133:   PetscFunctionReturn(PETSC_SUCCESS);
3134: }

3136: /*@
3137:   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).

3139:   Not Collective

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

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

3150:   Level: advanced

3152:   Notes:
3153:   Like `DMPlexGetConeTuple()` but recursive.

3155:   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.
3156:   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.

3158:   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\:
3159:   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3160:   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].

3162: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3163:           `DMPlexGetDepth()`, `PetscSection`, `IS`
3164: @*/
3165: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3166: {
3167:   const PetscInt *arr0 = NULL, *cone = NULL;
3168:   PetscInt       *arr = NULL, *newarr = NULL;
3169:   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3170:   IS             *expandedPoints_;
3171:   PetscSection   *sections_;

3173:   PetscFunctionBegin;
3176:   if (depth) PetscAssertPointer(depth, 3);
3177:   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
3178:   if (sections) PetscAssertPointer(sections, 5);
3179:   PetscCall(ISGetLocalSize(points, &n));
3180:   PetscCall(ISGetIndices(points, &arr0));
3181:   PetscCall(DMPlexGetDepth(dm, &depth_));
3182:   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
3183:   PetscCall(PetscCalloc1(depth_, &sections_));
3184:   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3185:   for (d = depth_ - 1; d >= 0; d--) {
3186:     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
3187:     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3188:     for (i = 0; i < n; i++) {
3189:       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3190:       if (arr[i] >= start && arr[i] < end) {
3191:         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
3192:         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3193:       } else {
3194:         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3195:       }
3196:     }
3197:     PetscCall(PetscSectionSetUp(sections_[d]));
3198:     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
3199:     PetscCall(PetscMalloc1(newn, &newarr));
3200:     for (i = 0; i < n; i++) {
3201:       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
3202:       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3203:       if (cn > 1) {
3204:         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3205:         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3206:       } else {
3207:         newarr[co] = arr[i];
3208:       }
3209:     }
3210:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3211:     arr = newarr;
3212:     n   = newn;
3213:   }
3214:   PetscCall(ISRestoreIndices(points, &arr0));
3215:   *depth = depth_;
3216:   if (expandedPoints) *expandedPoints = expandedPoints_;
3217:   else {
3218:     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
3219:     PetscCall(PetscFree(expandedPoints_));
3220:   }
3221:   if (sections) *sections = sections_;
3222:   else {
3223:     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
3224:     PetscCall(PetscFree(sections_));
3225:   }
3226:   PetscFunctionReturn(PETSC_SUCCESS);
3227: }

3229: /*@
3230:   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`

3232:   Not Collective

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

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

3243:   Level: advanced

3245:   Note:
3246:   See `DMPlexGetConeRecursive()`

3248: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3249:           `DMPlexGetDepth()`, `IS`, `PetscSection`
3250: @*/
3251: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3252: {
3253:   PetscInt d, depth_;

3255:   PetscFunctionBegin;
3256:   PetscCall(DMPlexGetDepth(dm, &depth_));
3257:   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3258:   if (depth) *depth = 0;
3259:   if (expandedPoints) {
3260:     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
3261:     PetscCall(PetscFree(*expandedPoints));
3262:   }
3263:   if (sections) {
3264:     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
3265:     PetscCall(PetscFree(*sections));
3266:   }
3267:   PetscFunctionReturn(PETSC_SUCCESS);
3268: }

3270: /*@
3271:   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

3273:   Not Collective

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

3280:   Level: beginner

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

3285: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3286: @*/
3287: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3288: {
3289:   DM_Plex *mesh = (DM_Plex *)dm->data;
3290:   PetscInt dof, off, c;

3292:   PetscFunctionBegin;
3294:   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3295:   if (dof) PetscAssertPointer(cone, 3);
3296:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3297:   if (PetscDefined(USE_DEBUG)) {
3298:     PetscInt pStart, pEnd;
3299:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3300:     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);
3301:     for (c = 0; c < dof; ++c) {
3302:       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);
3303:       mesh->cones[off + c] = cone[c];
3304:     }
3305:   } else {
3306:     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3307:   }
3308:   PetscFunctionReturn(PETSC_SUCCESS);
3309: }

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

3314:   Not Collective

3316:   Input Parameters:
3317: + dm - The `DMPLEX`
3318: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

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

3324:   Level: beginner

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

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

3336: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3337: @*/
3338: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3339: {
3340:   DM_Plex *mesh = (DM_Plex *)dm->data;
3341:   PetscInt off;

3343:   PetscFunctionBegin;
3345:   if (PetscDefined(USE_DEBUG)) {
3346:     PetscInt dof;
3347:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3348:     if (dof) PetscAssertPointer(coneOrientation, 3);
3349:   }
3350:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));

3352:   *coneOrientation = &mesh->coneOrientations[off];
3353:   PetscFunctionReturn(PETSC_SUCCESS);
3354: }

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

3359:   Not Collective

3361:   Input Parameters:
3362: + dm              - The `DMPLEX`
3363: . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3364: - coneOrientation - An array of orientations

3366:   Level: beginner

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

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

3373: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3374: @*/
3375: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3376: {
3377:   DM_Plex *mesh = (DM_Plex *)dm->data;
3378:   PetscInt pStart, pEnd;
3379:   PetscInt dof, off, c;

3381:   PetscFunctionBegin;
3383:   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3384:   if (dof) PetscAssertPointer(coneOrientation, 3);
3385:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3386:   if (PetscDefined(USE_DEBUG)) {
3387:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3388:     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);
3389:     for (c = 0; c < dof; ++c) {
3390:       PetscInt cdof, o = coneOrientation[c];

3392:       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
3393:       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);
3394:       mesh->coneOrientations[off + c] = o;
3395:     }
3396:   } else {
3397:     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3398:   }
3399:   PetscFunctionReturn(PETSC_SUCCESS);
3400: }

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

3405:   Not Collective

3407:   Input Parameters:
3408: + dm        - The `DMPLEX`
3409: . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
3410: . conePos   - The local index in the cone where the point should be put
3411: - conePoint - The mesh point to insert

3413:   Level: beginner

3415: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3416: @*/
3417: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3418: {
3419:   DM_Plex *mesh = (DM_Plex *)dm->data;
3420:   PetscInt pStart, pEnd;
3421:   PetscInt dof, off;

3423:   PetscFunctionBegin;
3425:   if (PetscDefined(USE_DEBUG)) {
3426:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3427:     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);
3428:     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);
3429:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3430:     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);
3431:   }
3432:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3433:   mesh->cones[off + conePos] = conePoint;
3434:   PetscFunctionReturn(PETSC_SUCCESS);
3435: }

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

3440:   Not Collective

3442:   Input Parameters:
3443: + dm              - The `DMPLEX`
3444: . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3445: . conePos         - The local index in the cone where the point should be put
3446: - coneOrientation - The point orientation to insert

3448:   Level: beginner

3450:   Note:
3451:   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.

3453: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3454: @*/
3455: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3456: {
3457:   DM_Plex *mesh = (DM_Plex *)dm->data;
3458:   PetscInt pStart, pEnd;
3459:   PetscInt dof, off;

3461:   PetscFunctionBegin;
3463:   if (PetscDefined(USE_DEBUG)) {
3464:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3465:     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);
3466:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3467:     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);
3468:   }
3469:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3470:   mesh->coneOrientations[off + conePos] = coneOrientation;
3471:   PetscFunctionReturn(PETSC_SUCCESS);
3472: }

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

3477:   Not collective

3479:   Input Parameters:
3480: + dm - The DMPlex
3481: - p  - The point, which must lie in the chart set with DMPlexSetChart()

3483:   Output Parameters:
3484: + cone - An array of points which are on the in-edges for point `p`
3485: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3486:         integer giving the prescription for cone traversal.

3488:   Level: beginner

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

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

3500: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3501: @*/
3502: PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3503: {
3504:   DM_Plex *mesh = (DM_Plex *)dm->data;

3506:   PetscFunctionBegin;
3508:   if (mesh->tr) {
3509:     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
3510:   } else {
3511:     PetscInt off;
3512:     if (PetscDefined(USE_DEBUG)) {
3513:       PetscInt dof;
3514:       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3515:       if (dof) {
3516:         if (cone) PetscAssertPointer(cone, 3);
3517:         if (ornt) PetscAssertPointer(ornt, 4);
3518:       }
3519:     }
3520:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3521:     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
3522:     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
3523:   }
3524:   PetscFunctionReturn(PETSC_SUCCESS);
3525: }

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

3530:   Not Collective

3532:   Input Parameters:
3533: + dm   - The DMPlex
3534: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3535: . cone - An array of points which are on the in-edges for point p
3536: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3537:         integer giving the prescription for cone traversal.

3539:   Level: beginner

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

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

3551: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3552: @*/
3553: PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3554: {
3555:   DM_Plex *mesh = (DM_Plex *)dm->data;

3557:   PetscFunctionBegin;
3559:   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
3560:   PetscFunctionReturn(PETSC_SUCCESS);
3561: }

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

3566:   Not Collective

3568:   Input Parameters:
3569: + dm - The `DMPLEX`
3570: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

3572:   Output Parameter:
3573: . size - The support size for point `p`

3575:   Level: beginner

3577: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3578: @*/
3579: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3580: {
3581:   DM_Plex *mesh = (DM_Plex *)dm->data;

3583:   PetscFunctionBegin;
3585:   PetscAssertPointer(size, 3);
3586:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3587:   PetscFunctionReturn(PETSC_SUCCESS);
3588: }

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

3593:   Not Collective

3595:   Input Parameters:
3596: + dm   - The `DMPLEX`
3597: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3598: - size - The support size for point `p`

3600:   Level: beginner

3602:   Note:
3603:   This should be called after `DMPlexSetChart()`.

3605: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3606: @*/
3607: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3608: {
3609:   DM_Plex *mesh = (DM_Plex *)dm->data;

3611:   PetscFunctionBegin;
3613:   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3614:   PetscFunctionReturn(PETSC_SUCCESS);
3615: }

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

3620:   Not Collective

3622:   Input Parameters:
3623: + dm - The `DMPLEX`
3624: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

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

3629:   Level: beginner

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

3635: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3636: @*/
3637: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3638: {
3639:   DM_Plex *mesh = (DM_Plex *)dm->data;
3640:   PetscInt off;

3642:   PetscFunctionBegin;
3644:   PetscAssertPointer(support, 3);
3645:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3646:   *support = PetscSafePointerPlusOffset(mesh->supports, off);
3647:   PetscFunctionReturn(PETSC_SUCCESS);
3648: }

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

3653:   Not Collective

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

3660:   Level: beginner

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

3665: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3666: @*/
3667: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3668: {
3669:   DM_Plex *mesh = (DM_Plex *)dm->data;
3670:   PetscInt pStart, pEnd;
3671:   PetscInt dof, off, c;

3673:   PetscFunctionBegin;
3675:   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3676:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3677:   if (dof) PetscAssertPointer(support, 3);
3678:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3679:   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);
3680:   for (c = 0; c < dof; ++c) {
3681:     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);
3682:     mesh->supports[off + c] = support[c];
3683:   }
3684:   PetscFunctionReturn(PETSC_SUCCESS);
3685: }

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

3690:   Not Collective

3692:   Input Parameters:
3693: + dm           - The `DMPLEX`
3694: . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
3695: . supportPos   - The local index in the cone where the point should be put
3696: - supportPoint - The mesh point to insert

3698:   Level: beginner

3700: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3701: @*/
3702: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3703: {
3704:   DM_Plex *mesh = (DM_Plex *)dm->data;
3705:   PetscInt pStart, pEnd;
3706:   PetscInt dof, off;

3708:   PetscFunctionBegin;
3710:   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3711:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3712:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3713:   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);
3714:   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);
3715:   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);
3716:   mesh->supports[off + supportPos] = supportPoint;
3717:   PetscFunctionReturn(PETSC_SUCCESS);
3718: }

3720: /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3721: PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3722: {
3723:   switch (ct) {
3724:   case DM_POLYTOPE_SEGMENT:
3725:     if (o == -1) return -2;
3726:     break;
3727:   case DM_POLYTOPE_TRIANGLE:
3728:     if (o == -3) return -1;
3729:     if (o == -2) return -3;
3730:     if (o == -1) return -2;
3731:     break;
3732:   case DM_POLYTOPE_QUADRILATERAL:
3733:     if (o == -4) return -2;
3734:     if (o == -3) return -1;
3735:     if (o == -2) return -4;
3736:     if (o == -1) return -3;
3737:     break;
3738:   default:
3739:     return o;
3740:   }
3741:   return o;
3742: }

3744: /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3745: PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3746: {
3747:   switch (ct) {
3748:   case DM_POLYTOPE_SEGMENT:
3749:     if ((o == -2) || (o == 1)) return -1;
3750:     if (o == -1) return 0;
3751:     break;
3752:   case DM_POLYTOPE_TRIANGLE:
3753:     if (o == -3) return -2;
3754:     if (o == -2) return -1;
3755:     if (o == -1) return -3;
3756:     break;
3757:   case DM_POLYTOPE_QUADRILATERAL:
3758:     if (o == -4) return -2;
3759:     if (o == -3) return -1;
3760:     if (o == -2) return -4;
3761:     if (o == -1) return -3;
3762:     break;
3763:   default:
3764:     return o;
3765:   }
3766:   return o;
3767: }

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

3774:   PetscFunctionBegin;
3775:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3776:   for (p = pStart; p < pEnd; ++p) {
3777:     const PetscInt *cone, *ornt;
3778:     PetscInt        coneSize, c;

3780:     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
3781:     PetscCall(DMPlexGetCone(dm, p, &cone));
3782:     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3783:     for (c = 0; c < coneSize; ++c) {
3784:       DMPolytopeType ct;
3785:       const PetscInt o = ornt[c];

3787:       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3788:       switch (ct) {
3789:       case DM_POLYTOPE_SEGMENT:
3790:         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3791:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3792:         break;
3793:       case DM_POLYTOPE_TRIANGLE:
3794:         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3795:         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3796:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3797:         break;
3798:       case DM_POLYTOPE_QUADRILATERAL:
3799:         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3800:         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3801:         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
3802:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3803:         break;
3804:       default:
3805:         break;
3806:       }
3807:     }
3808:   }
3809:   PetscFunctionReturn(PETSC_SUCCESS);
3810: }

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

3816:   PetscFunctionBeginHot;
3817:   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3818:     if (useCone) {
3819:       PetscCall(DMPlexGetConeSize(dm, p, size));
3820:       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
3821:     } else {
3822:       PetscCall(DMPlexGetSupportSize(dm, p, size));
3823:       PetscCall(DMPlexGetSupport(dm, p, arr));
3824:     }
3825:   } else {
3826:     if (useCone) {
3827:       const PetscSection s   = mesh->coneSection;
3828:       const PetscInt     ps  = p - s->pStart;
3829:       const PetscInt     off = s->atlasOff[ps];

3831:       *size = s->atlasDof[ps];
3832:       *arr  = mesh->cones + off;
3833:       *ornt = mesh->coneOrientations + off;
3834:     } else {
3835:       const PetscSection s   = mesh->supportSection;
3836:       const PetscInt     ps  = p - s->pStart;
3837:       const PetscInt     off = s->atlasOff[ps];

3839:       *size = s->atlasDof[ps];
3840:       *arr  = mesh->supports + off;
3841:     }
3842:   }
3843:   PetscFunctionReturn(PETSC_SUCCESS);
3844: }

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

3850:   PetscFunctionBeginHot;
3851:   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3852:     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
3853:   }
3854:   PetscFunctionReturn(PETSC_SUCCESS);
3855: }

3857: static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3858: {
3859:   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3860:   PetscInt       *closure;
3861:   const PetscInt *tmp = NULL, *tmpO = NULL;
3862:   PetscInt        off = 0, tmpSize, t;

3864:   PetscFunctionBeginHot;
3865:   if (ornt) {
3866:     PetscCall(DMPlexGetCellType(dm, p, &ct));
3867:     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN;
3868:   }
3869:   if (*points) {
3870:     closure = *points;
3871:   } else {
3872:     PetscInt maxConeSize, maxSupportSize;
3873:     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3874:     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3875:   }
3876:   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3877:   if (ct == DM_POLYTOPE_UNKNOWN) {
3878:     closure[off++] = p;
3879:     closure[off++] = 0;
3880:     for (t = 0; t < tmpSize; ++t) {
3881:       closure[off++] = tmp[t];
3882:       closure[off++] = tmpO ? tmpO[t] : 0;
3883:     }
3884:   } else {
3885:     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);

3887:     /* We assume that cells with a valid type have faces with a valid type */
3888:     closure[off++] = p;
3889:     closure[off++] = ornt;
3890:     for (t = 0; t < tmpSize; ++t) {
3891:       DMPolytopeType ft;

3893:       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3894:       closure[off++] = tmp[arr[t]];
3895:       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3896:     }
3897:   }
3898:   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3899:   if (numPoints) *numPoints = tmpSize + 1;
3900:   if (points) *points = closure;
3901:   PetscFunctionReturn(PETSC_SUCCESS);
3902: }

3904: /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3905: static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3906: {
3907:   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
3908:   const PetscInt *cone, *ornt;
3909:   PetscInt       *pts, *closure = NULL;
3910:   DMPolytopeType  ft;
3911:   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3912:   PetscInt        dim, coneSize, c, d, clSize, cl;

3914:   PetscFunctionBeginHot;
3915:   PetscCall(DMGetDimension(dm, &dim));
3916:   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3917:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3918:   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3919:   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3920:   maxSize       = PetscMax(coneSeries, supportSeries);
3921:   if (*points) {
3922:     pts = *points;
3923:   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3924:   c        = 0;
3925:   pts[c++] = point;
3926:   pts[c++] = o;
3927:   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
3928:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
3929:   for (cl = 0; cl < clSize * 2; cl += 2) {
3930:     pts[c++] = closure[cl];
3931:     pts[c++] = closure[cl + 1];
3932:   }
3933:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
3934:   for (cl = 0; cl < clSize * 2; cl += 2) {
3935:     pts[c++] = closure[cl];
3936:     pts[c++] = closure[cl + 1];
3937:   }
3938:   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3939:   for (d = 2; d < coneSize; ++d) {
3940:     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3941:     pts[c++] = cone[arr[d * 2 + 0]];
3942:     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3943:   }
3944:   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3945:   if (dim >= 3) {
3946:     for (d = 2; d < coneSize; ++d) {
3947:       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3948:       const PetscInt *fcone, *fornt;
3949:       PetscInt        fconeSize, fc, i;

3951:       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3952:       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
3953:       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3954:       for (fc = 0; fc < fconeSize; ++fc) {
3955:         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3956:         const PetscInt co = farr[fc * 2 + 1];

3958:         for (i = 0; i < c; i += 2)
3959:           if (pts[i] == cp) break;
3960:         if (i == c) {
3961:           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3962:           pts[c++] = cp;
3963:           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3964:         }
3965:       }
3966:       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3967:     }
3968:   }
3969:   *numPoints = c / 2;
3970:   *points    = pts;
3971:   PetscFunctionReturn(PETSC_SUCCESS);
3972: }

3974: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3975: {
3976:   DMPolytopeType ct;
3977:   PetscInt      *closure, *fifo;
3978:   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3979:   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3980:   PetscInt       depth, maxSize;

3982:   PetscFunctionBeginHot;
3983:   PetscCall(DMPlexGetDepth(dm, &depth));
3984:   if (depth == 1) {
3985:     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3986:     PetscFunctionReturn(PETSC_SUCCESS);
3987:   }
3988:   PetscCall(DMPlexGetCellType(dm, p, &ct));
3989:   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN;
3990:   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
3991:     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3992:     PetscFunctionReturn(PETSC_SUCCESS);
3993:   }
3994:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3995:   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3996:   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3997:   maxSize       = PetscMax(coneSeries, supportSeries);
3998:   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3999:   if (*points) {
4000:     closure = *points;
4001:   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
4002:   closure[closureSize++] = p;
4003:   closure[closureSize++] = ornt;
4004:   fifo[fifoSize++]       = p;
4005:   fifo[fifoSize++]       = ornt;
4006:   fifo[fifoSize++]       = ct;
4007:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
4008:   while (fifoSize - fifoStart) {
4009:     const PetscInt       q    = fifo[fifoStart++];
4010:     const PetscInt       o    = fifo[fifoStart++];
4011:     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
4012:     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
4013:     const PetscInt      *tmp, *tmpO = NULL;
4014:     PetscInt             tmpSize, t;

4016:     if (PetscDefined(USE_DEBUG)) {
4017:       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
4018:       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);
4019:     }
4020:     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4021:     for (t = 0; t < tmpSize; ++t) {
4022:       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4023:       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4024:       const PetscInt cp = tmp[ip];
4025:       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4026:       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4027:       PetscInt       c;

4029:       /* Check for duplicate */
4030:       for (c = 0; c < closureSize; c += 2) {
4031:         if (closure[c] == cp) break;
4032:       }
4033:       if (c == closureSize) {
4034:         closure[closureSize++] = cp;
4035:         closure[closureSize++] = co;
4036:         fifo[fifoSize++]       = cp;
4037:         fifo[fifoSize++]       = co;
4038:         fifo[fifoSize++]       = ct;
4039:       }
4040:     }
4041:     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4042:   }
4043:   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4044:   if (numPoints) *numPoints = closureSize / 2;
4045:   if (points) *points = closure;
4046:   PetscFunctionReturn(PETSC_SUCCESS);
4047: }

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

4052:   Not Collective

4054:   Input Parameters:
4055: + dm      - The `DMPLEX`
4056: . p       - The mesh point
4057: - useCone - `PETSC_TRUE` for the closure, otherwise return the star

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

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

4066:   Level: beginner

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

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

4074: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4075: @*/
4076: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4077: {
4078:   PetscFunctionBeginHot;
4080:   if (numPoints) PetscAssertPointer(numPoints, 4);
4081:   if (points) PetscAssertPointer(points, 5);
4082:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
4083:   PetscFunctionReturn(PETSC_SUCCESS);
4084: }

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

4089:   Not Collective

4091:   Input Parameters:
4092: + dm        - The `DMPLEX`
4093: . p         - The mesh point
4094: . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
4095: . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4096: - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

4098:   Level: beginner

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

4103: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4104: @*/
4105: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4106: {
4107:   PetscFunctionBeginHot;
4109:   if (numPoints) *numPoints = 0;
4110:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
4111:   PetscFunctionReturn(PETSC_SUCCESS);
4112: }

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

4117:   Not Collective

4119:   Input Parameter:
4120: . dm - The `DMPLEX`

4122:   Output Parameters:
4123: + maxConeSize    - The maximum number of in-edges
4124: - maxSupportSize - The maximum number of out-edges

4126:   Level: beginner

4128: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4129: @*/
4130: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
4131: {
4132:   DM_Plex *mesh = (DM_Plex *)dm->data;

4134:   PetscFunctionBegin;
4136:   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
4137:   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
4138:   PetscFunctionReturn(PETSC_SUCCESS);
4139: }

4141: PetscErrorCode DMSetUp_Plex(DM dm)
4142: {
4143:   DM_Plex *mesh = (DM_Plex *)dm->data;
4144:   PetscInt size, maxSupportSize;

4146:   PetscFunctionBegin;
4148:   PetscCall(PetscSectionSetUp(mesh->coneSection));
4149:   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
4150:   PetscCall(PetscMalloc1(size, &mesh->cones));
4151:   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
4152:   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4153:   if (maxSupportSize) {
4154:     PetscCall(PetscSectionSetUp(mesh->supportSection));
4155:     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
4156:     PetscCall(PetscMalloc1(size, &mesh->supports));
4157:   }
4158:   PetscFunctionReturn(PETSC_SUCCESS);
4159: }

4161: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4162: {
4163:   PetscFunctionBegin;
4164:   if (subdm) PetscCall(DMClone(dm, subdm));
4165:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
4166:   if (subdm) (*subdm)->useNatural = dm->useNatural;
4167:   if (dm->useNatural && dm->sfMigration) {
4168:     PetscSF sfNatural;

4170:     (*subdm)->sfMigration = dm->sfMigration;
4171:     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
4172:     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4173:     (*subdm)->sfNatural = sfNatural;
4174:   }
4175:   PetscFunctionReturn(PETSC_SUCCESS);
4176: }

4178: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4179: {
4180:   PetscInt i = 0;

4182:   PetscFunctionBegin;
4183:   PetscCall(DMClone(dms[0], superdm));
4184:   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4185:   (*superdm)->useNatural = PETSC_FALSE;
4186:   for (i = 0; i < len; i++) {
4187:     if (dms[i]->useNatural && dms[i]->sfMigration) {
4188:       PetscSF sfNatural;

4190:       (*superdm)->sfMigration = dms[i]->sfMigration;
4191:       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4192:       (*superdm)->useNatural = PETSC_TRUE;
4193:       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4194:       (*superdm)->sfNatural = sfNatural;
4195:       break;
4196:     }
4197:   }
4198:   PetscFunctionReturn(PETSC_SUCCESS);
4199: }

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

4204:   Not Collective

4206:   Input Parameter:
4207: . dm - The `DMPLEX`

4209:   Level: beginner

4211:   Note:
4212:   This should be called after all calls to `DMPlexSetCone()`

4214: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4215: @*/
4216: PetscErrorCode DMPlexSymmetrize(DM dm)
4217: {
4218:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4219:   PetscInt *offsets;
4220:   PetscInt  supportSize;
4221:   PetscInt  pStart, pEnd, p;

4223:   PetscFunctionBegin;
4225:   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
4226:   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4227:   /* Calculate support sizes */
4228:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4229:   for (p = pStart; p < pEnd; ++p) {
4230:     PetscInt dof, off, c;

4232:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4233:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4234:     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4235:   }
4236:   PetscCall(PetscSectionSetUp(mesh->supportSection));
4237:   /* Calculate supports */
4238:   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
4239:   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
4240:   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4241:   for (p = pStart; p < pEnd; ++p) {
4242:     PetscInt dof, off, c;

4244:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4245:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4246:     for (c = off; c < off + dof; ++c) {
4247:       const PetscInt q = mesh->cones[c];
4248:       PetscInt       offS;

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

4252:       mesh->supports[offS + offsets[q]] = p;
4253:       ++offsets[q];
4254:     }
4255:   }
4256:   PetscCall(PetscFree(offsets));
4257:   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
4258:   PetscFunctionReturn(PETSC_SUCCESS);
4259: }

4261: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4262: {
4263:   IS stratumIS;

4265:   PetscFunctionBegin;
4266:   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
4267:   if (PetscDefined(USE_DEBUG)) {
4268:     PetscInt  qStart, qEnd, numLevels, level;
4269:     PetscBool overlap = PETSC_FALSE;
4270:     PetscCall(DMLabelGetNumValues(label, &numLevels));
4271:     for (level = 0; level < numLevels; level++) {
4272:       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4273:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
4274:         overlap = PETSC_TRUE;
4275:         break;
4276:       }
4277:     }
4278:     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);
4279:   }
4280:   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
4281:   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
4282:   PetscCall(ISDestroy(&stratumIS));
4283:   PetscFunctionReturn(PETSC_SUCCESS);
4284: }

4286: static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4287: {
4288:   PetscInt *pMin, *pMax;
4289:   PetscInt  pStart, pEnd;
4290:   PetscInt  dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT;

4292:   PetscFunctionBegin;
4293:   {
4294:     DMLabel label2;

4296:     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4297:     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4298:   }
4299:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4300:   for (PetscInt p = pStart; p < pEnd; ++p) {
4301:     DMPolytopeType ct;

4303:     PetscCall(DMPlexGetCellType(dm, p, &ct));
4304:     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4305:     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4306:   }
4307:   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4308:   for (PetscInt d = dmin; d <= dmax; ++d) {
4309:     pMin[d] = PETSC_MAX_INT;
4310:     pMax[d] = PETSC_MIN_INT;
4311:   }
4312:   for (PetscInt p = pStart; p < pEnd; ++p) {
4313:     DMPolytopeType ct;
4314:     PetscInt       d;

4316:     PetscCall(DMPlexGetCellType(dm, p, &ct));
4317:     d       = DMPolytopeTypeGetDim(ct);
4318:     pMin[d] = PetscMin(p, pMin[d]);
4319:     pMax[d] = PetscMax(p, pMax[d]);
4320:   }
4321:   for (PetscInt d = dmin; d <= dmax; ++d) {
4322:     if (pMin[d] > pMax[d]) continue;
4323:     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4324:   }
4325:   PetscCall(PetscFree2(pMin, pMax));
4326:   PetscFunctionReturn(PETSC_SUCCESS);
4327: }

4329: static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4330: {
4331:   PetscInt pStart, pEnd;
4332:   PetscInt numRoots = 0, numLeaves = 0;

4334:   PetscFunctionBegin;
4335:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4336:   {
4337:     /* Initialize roots and count leaves */
4338:     PetscInt sMin = PETSC_MAX_INT;
4339:     PetscInt sMax = PETSC_MIN_INT;
4340:     PetscInt coneSize, supportSize;

4342:     for (PetscInt p = pStart; p < pEnd; ++p) {
4343:       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4344:       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4345:       if (!coneSize && supportSize) {
4346:         sMin = PetscMin(p, sMin);
4347:         sMax = PetscMax(p, sMax);
4348:         ++numRoots;
4349:       } else if (!supportSize && coneSize) {
4350:         ++numLeaves;
4351:       } else if (!supportSize && !coneSize) {
4352:         /* Isolated points */
4353:         sMin = PetscMin(p, sMin);
4354:         sMax = PetscMax(p, sMax);
4355:       }
4356:     }
4357:     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4358:   }

4360:   if (numRoots + numLeaves == (pEnd - pStart)) {
4361:     PetscInt sMin = PETSC_MAX_INT;
4362:     PetscInt sMax = PETSC_MIN_INT;
4363:     PetscInt coneSize, supportSize;

4365:     for (PetscInt p = pStart; p < pEnd; ++p) {
4366:       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4367:       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4368:       if (!supportSize && coneSize) {
4369:         sMin = PetscMin(p, sMin);
4370:         sMax = PetscMax(p, sMax);
4371:       }
4372:     }
4373:     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4374:   } else {
4375:     PetscInt level = 0;
4376:     PetscInt qStart, qEnd;

4378:     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4379:     while (qEnd > qStart) {
4380:       PetscInt sMin = PETSC_MAX_INT;
4381:       PetscInt sMax = PETSC_MIN_INT;

4383:       for (PetscInt q = qStart; q < qEnd; ++q) {
4384:         const PetscInt *support;
4385:         PetscInt        supportSize;

4387:         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4388:         PetscCall(DMPlexGetSupport(dm, q, &support));
4389:         for (PetscInt s = 0; s < supportSize; ++s) {
4390:           sMin = PetscMin(support[s], sMin);
4391:           sMax = PetscMax(support[s], sMax);
4392:         }
4393:       }
4394:       PetscCall(DMLabelGetNumValues(label, &level));
4395:       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4396:       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4397:     }
4398:   }
4399:   PetscFunctionReturn(PETSC_SUCCESS);
4400: }

4402: /*@
4403:   DMPlexStratify - Computes the strata for all points in the `DMPLEX`

4405:   Collective

4407:   Input Parameter:
4408: . dm - The `DMPLEX`

4410:   Level: beginner

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

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

4424:   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4425:   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4426:   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
4427:   to interpolate only that one (e0), so that
4428: .vb
4429:   cone(c0) = {e0, v2}
4430:   cone(e0) = {v0, v1}
4431: .ve
4432:   If `DMPlexStratify()` is run on this mesh, it will give depths
4433: .vb
4434:    depth 0 = {v0, v1, v2}
4435:    depth 1 = {e0, c0}
4436: .ve
4437:   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.

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

4441: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4442: @*/
4443: PetscErrorCode DMPlexStratify(DM dm)
4444: {
4445:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4446:   DMLabel   label;
4447:   PetscBool flg = PETSC_FALSE;

4449:   PetscFunctionBegin;
4451:   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));

4453:   // Create depth label
4454:   PetscCall(DMRemoveLabel(dm, "depth", NULL));
4455:   PetscCall(DMCreateLabel(dm, "depth"));
4456:   PetscCall(DMPlexGetDepthLabel(dm, &label));

4458:   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4459:   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4460:   else PetscCall(DMPlexStratify_Topological_Private(dm, label));

4462:   { /* just in case there is an empty process */
4463:     PetscInt numValues, maxValues = 0, v;

4465:     PetscCall(DMLabelGetNumValues(label, &numValues));
4466:     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
4467:     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4468:   }
4469:   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
4470:   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
4471:   PetscFunctionReturn(PETSC_SUCCESS);
4472: }

4474: PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4475: {
4476:   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4477:   PetscInt       dim, depth, pheight, coneSize;

4479:   PetscFunctionBeginHot;
4480:   PetscCall(DMGetDimension(dm, &dim));
4481:   PetscCall(DMPlexGetDepth(dm, &depth));
4482:   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4483:   pheight = depth - pdepth;
4484:   if (depth <= 1) {
4485:     switch (pdepth) {
4486:     case 0:
4487:       ct = DM_POLYTOPE_POINT;
4488:       break;
4489:     case 1:
4490:       switch (coneSize) {
4491:       case 2:
4492:         ct = DM_POLYTOPE_SEGMENT;
4493:         break;
4494:       case 3:
4495:         ct = DM_POLYTOPE_TRIANGLE;
4496:         break;
4497:       case 4:
4498:         switch (dim) {
4499:         case 2:
4500:           ct = DM_POLYTOPE_QUADRILATERAL;
4501:           break;
4502:         case 3:
4503:           ct = DM_POLYTOPE_TETRAHEDRON;
4504:           break;
4505:         default:
4506:           break;
4507:         }
4508:         break;
4509:       case 5:
4510:         ct = DM_POLYTOPE_PYRAMID;
4511:         break;
4512:       case 6:
4513:         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4514:         break;
4515:       case 8:
4516:         ct = DM_POLYTOPE_HEXAHEDRON;
4517:         break;
4518:       default:
4519:         break;
4520:       }
4521:     }
4522:   } else {
4523:     if (pdepth == 0) {
4524:       ct = DM_POLYTOPE_POINT;
4525:     } else if (pheight == 0) {
4526:       switch (dim) {
4527:       case 1:
4528:         switch (coneSize) {
4529:         case 2:
4530:           ct = DM_POLYTOPE_SEGMENT;
4531:           break;
4532:         default:
4533:           break;
4534:         }
4535:         break;
4536:       case 2:
4537:         switch (coneSize) {
4538:         case 3:
4539:           ct = DM_POLYTOPE_TRIANGLE;
4540:           break;
4541:         case 4:
4542:           ct = DM_POLYTOPE_QUADRILATERAL;
4543:           break;
4544:         default:
4545:           break;
4546:         }
4547:         break;
4548:       case 3:
4549:         switch (coneSize) {
4550:         case 4:
4551:           ct = DM_POLYTOPE_TETRAHEDRON;
4552:           break;
4553:         case 5: {
4554:           const PetscInt *cone;
4555:           PetscInt        faceConeSize;

4557:           PetscCall(DMPlexGetCone(dm, p, &cone));
4558:           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4559:           switch (faceConeSize) {
4560:           case 3:
4561:             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4562:             break;
4563:           case 4:
4564:             ct = DM_POLYTOPE_PYRAMID;
4565:             break;
4566:           }
4567:         } break;
4568:         case 6:
4569:           ct = DM_POLYTOPE_HEXAHEDRON;
4570:           break;
4571:         default:
4572:           break;
4573:         }
4574:         break;
4575:       default:
4576:         break;
4577:       }
4578:     } else if (pheight > 0) {
4579:       switch (coneSize) {
4580:       case 2:
4581:         ct = DM_POLYTOPE_SEGMENT;
4582:         break;
4583:       case 3:
4584:         ct = DM_POLYTOPE_TRIANGLE;
4585:         break;
4586:       case 4:
4587:         ct = DM_POLYTOPE_QUADRILATERAL;
4588:         break;
4589:       default:
4590:         break;
4591:       }
4592:     }
4593:   }
4594:   *pt = ct;
4595:   PetscFunctionReturn(PETSC_SUCCESS);
4596: }

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

4601:   Collective

4603:   Input Parameter:
4604: . dm - The `DMPLEX`

4606:   Level: developer

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

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

4615: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4616: @*/
4617: PetscErrorCode DMPlexComputeCellTypes(DM dm)
4618: {
4619:   DM_Plex *mesh;
4620:   DMLabel  ctLabel;
4621:   PetscInt pStart, pEnd, p;

4623:   PetscFunctionBegin;
4625:   mesh = (DM_Plex *)dm->data;
4626:   PetscCall(DMCreateLabel(dm, "celltype"));
4627:   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
4628:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4629:   PetscCall(PetscFree(mesh->cellTypes));
4630:   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4631:   for (p = pStart; p < pEnd; ++p) {
4632:     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4633:     PetscInt       pdepth;

4635:     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
4636:     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4637:     PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]);
4638:     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4639:     mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4640:   }
4641:   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
4642:   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
4643:   PetscFunctionReturn(PETSC_SUCCESS);
4644: }

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

4649:   Not Collective

4651:   Input Parameters:
4652: + dm        - The `DMPLEX` object
4653: . numPoints - The number of input points for the join
4654: - points    - The input points

4656:   Output Parameters:
4657: + numCoveredPoints - The number of points in the join
4658: - coveredPoints    - The points in the join

4660:   Level: intermediate

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

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

4668: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4669: @*/
4670: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4671: {
4672:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4673:   PetscInt *join[2];
4674:   PetscInt  joinSize, i = 0;
4675:   PetscInt  dof, off, p, c, m;
4676:   PetscInt  maxSupportSize;

4678:   PetscFunctionBegin;
4680:   PetscAssertPointer(points, 3);
4681:   PetscAssertPointer(numCoveredPoints, 4);
4682:   PetscAssertPointer(coveredPoints, 5);
4683:   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4684:   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
4685:   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4686:   /* Copy in support of first point */
4687:   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
4688:   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4689:   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4690:   /* Check each successive support */
4691:   for (p = 1; p < numPoints; ++p) {
4692:     PetscInt newJoinSize = 0;

4694:     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
4695:     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4696:     for (c = 0; c < dof; ++c) {
4697:       const PetscInt point = mesh->supports[off + c];

4699:       for (m = 0; m < joinSize; ++m) {
4700:         if (point == join[i][m]) {
4701:           join[1 - i][newJoinSize++] = point;
4702:           break;
4703:         }
4704:       }
4705:     }
4706:     joinSize = newJoinSize;
4707:     i        = 1 - i;
4708:   }
4709:   *numCoveredPoints = joinSize;
4710:   *coveredPoints    = join[i];
4711:   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
4712:   PetscFunctionReturn(PETSC_SUCCESS);
4713: }

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

4718:   Not Collective

4720:   Input Parameters:
4721: + dm        - The `DMPLEX` object
4722: . numPoints - The number of input points for the join
4723: - points    - The input points

4725:   Output Parameters:
4726: + numCoveredPoints - The number of points in the join
4727: - coveredPoints    - The points in the join

4729:   Level: intermediate

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

4734: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4735: @*/
4736: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4737: {
4738:   PetscFunctionBegin;
4740:   if (points) PetscAssertPointer(points, 3);
4741:   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4742:   PetscAssertPointer(coveredPoints, 5);
4743:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4744:   if (numCoveredPoints) *numCoveredPoints = 0;
4745:   PetscFunctionReturn(PETSC_SUCCESS);
4746: }

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

4751:   Not Collective

4753:   Input Parameters:
4754: + dm        - The `DMPLEX` object
4755: . numPoints - The number of input points for the join
4756: - points    - The input points

4758:   Output Parameters:
4759: + numCoveredPoints - The number of points in the join
4760: - coveredPoints    - The points in the join

4762:   Level: intermediate

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

4767: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4768: @*/
4769: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4770: {
4771:   PetscInt *offsets, **closures;
4772:   PetscInt *join[2];
4773:   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
4774:   PetscInt  p, d, c, m, ms;

4776:   PetscFunctionBegin;
4778:   PetscAssertPointer(points, 3);
4779:   PetscAssertPointer(numCoveredPoints, 4);
4780:   PetscAssertPointer(coveredPoints, 5);

4782:   PetscCall(DMPlexGetDepth(dm, &depth));
4783:   PetscCall(PetscCalloc1(numPoints, &closures));
4784:   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4785:   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
4786:   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
4787:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
4788:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));

4790:   for (p = 0; p < numPoints; ++p) {
4791:     PetscInt closureSize;

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

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

4799:       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4800:       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4801:         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4802:           offsets[p * (depth + 2) + d + 1] = i;
4803:           break;
4804:         }
4805:       }
4806:       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4807:     }
4808:     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);
4809:   }
4810:   for (d = 0; d < depth + 1; ++d) {
4811:     PetscInt dof;

4813:     /* Copy in support of first point */
4814:     dof = offsets[d + 1] - offsets[d];
4815:     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4816:     /* Check each successive cone */
4817:     for (p = 1; p < numPoints && joinSize; ++p) {
4818:       PetscInt newJoinSize = 0;

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

4824:         for (m = 0; m < joinSize; ++m) {
4825:           if (point == join[i][m]) {
4826:             join[1 - i][newJoinSize++] = point;
4827:             break;
4828:           }
4829:         }
4830:       }
4831:       joinSize = newJoinSize;
4832:       i        = 1 - i;
4833:     }
4834:     if (joinSize) break;
4835:   }
4836:   *numCoveredPoints = joinSize;
4837:   *coveredPoints    = join[i];
4838:   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4839:   PetscCall(PetscFree(closures));
4840:   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4841:   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
4842:   PetscFunctionReturn(PETSC_SUCCESS);
4843: }

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

4848:   Not Collective

4850:   Input Parameters:
4851: + dm        - The `DMPLEX` object
4852: . numPoints - The number of input points for the meet
4853: - points    - The input points

4855:   Output Parameters:
4856: + numCoveringPoints - The number of points in the meet
4857: - coveringPoints    - The points in the meet

4859:   Level: intermediate

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

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

4867: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4868: @*/
4869: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4870: {
4871:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4872:   PetscInt *meet[2];
4873:   PetscInt  meetSize, i = 0;
4874:   PetscInt  dof, off, p, c, m;
4875:   PetscInt  maxConeSize;

4877:   PetscFunctionBegin;
4879:   PetscAssertPointer(points, 3);
4880:   PetscAssertPointer(numCoveringPoints, 4);
4881:   PetscAssertPointer(coveringPoints, 5);
4882:   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
4883:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
4884:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4885:   /* Copy in cone of first point */
4886:   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
4887:   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4888:   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4889:   /* Check each successive cone */
4890:   for (p = 1; p < numPoints; ++p) {
4891:     PetscInt newMeetSize = 0;

4893:     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
4894:     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4895:     for (c = 0; c < dof; ++c) {
4896:       const PetscInt point = mesh->cones[off + c];

4898:       for (m = 0; m < meetSize; ++m) {
4899:         if (point == meet[i][m]) {
4900:           meet[1 - i][newMeetSize++] = point;
4901:           break;
4902:         }
4903:       }
4904:     }
4905:     meetSize = newMeetSize;
4906:     i        = 1 - i;
4907:   }
4908:   *numCoveringPoints = meetSize;
4909:   *coveringPoints    = meet[i];
4910:   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
4911:   PetscFunctionReturn(PETSC_SUCCESS);
4912: }

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

4917:   Not Collective

4919:   Input Parameters:
4920: + dm        - The `DMPLEX` object
4921: . numPoints - The number of input points for the meet
4922: - points    - The input points

4924:   Output Parameters:
4925: + numCoveredPoints - The number of points in the meet
4926: - coveredPoints    - The points in the meet

4928:   Level: intermediate

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

4933: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4934: @*/
4935: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4936: {
4937:   PetscFunctionBegin;
4939:   if (points) PetscAssertPointer(points, 3);
4940:   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4941:   PetscAssertPointer(coveredPoints, 5);
4942:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4943:   if (numCoveredPoints) *numCoveredPoints = 0;
4944:   PetscFunctionReturn(PETSC_SUCCESS);
4945: }

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

4950:   Not Collective

4952:   Input Parameters:
4953: + dm        - The `DMPLEX` object
4954: . numPoints - The number of input points for the meet
4955: - points    - The input points

4957:   Output Parameters:
4958: + numCoveredPoints - The number of points in the meet
4959: - coveredPoints    - The points in the meet

4961:   Level: intermediate

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

4966: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4967: @*/
4968: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4969: {
4970:   PetscInt *offsets, **closures;
4971:   PetscInt *meet[2];
4972:   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
4973:   PetscInt  p, h, c, m, mc;

4975:   PetscFunctionBegin;
4977:   PetscAssertPointer(points, 3);
4978:   PetscAssertPointer(numCoveredPoints, 4);
4979:   PetscAssertPointer(coveredPoints, 5);

4981:   PetscCall(DMPlexGetDepth(dm, &height));
4982:   PetscCall(PetscMalloc1(numPoints, &closures));
4983:   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
4984:   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
4985:   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
4986:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
4987:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));

4989:   for (p = 0; p < numPoints; ++p) {
4990:     PetscInt closureSize;

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

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

4998:       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4999:       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
5000:         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
5001:           offsets[p * (height + 2) + h + 1] = i;
5002:           break;
5003:         }
5004:       }
5005:       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
5006:     }
5007:     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);
5008:   }
5009:   for (h = 0; h < height + 1; ++h) {
5010:     PetscInt dof;

5012:     /* Copy in cone of first point */
5013:     dof = offsets[h + 1] - offsets[h];
5014:     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
5015:     /* Check each successive cone */
5016:     for (p = 1; p < numPoints && meetSize; ++p) {
5017:       PetscInt newMeetSize = 0;

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

5023:         for (m = 0; m < meetSize; ++m) {
5024:           if (point == meet[i][m]) {
5025:             meet[1 - i][newMeetSize++] = point;
5026:             break;
5027:           }
5028:         }
5029:       }
5030:       meetSize = newMeetSize;
5031:       i        = 1 - i;
5032:     }
5033:     if (meetSize) break;
5034:   }
5035:   *numCoveredPoints = meetSize;
5036:   *coveredPoints    = meet[i];
5037:   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
5038:   PetscCall(PetscFree(closures));
5039:   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
5040:   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
5041:   PetscFunctionReturn(PETSC_SUCCESS);
5042: }

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

5047:   Not Collective

5049:   Input Parameters:
5050: + dmA - A `DMPLEX` object
5051: - dmB - A `DMPLEX` object

5053:   Output Parameter:
5054: . equal - `PETSC_TRUE` if the topologies are identical

5056:   Level: intermediate

5058:   Note:
5059:   We are not solving graph isomorphism, so we do not permute.

5061: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
5062: @*/
5063: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5064: {
5065:   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;

5067:   PetscFunctionBegin;
5070:   PetscAssertPointer(equal, 3);

5072:   *equal = PETSC_FALSE;
5073:   PetscCall(DMPlexGetDepth(dmA, &depth));
5074:   PetscCall(DMPlexGetDepth(dmB, &depthB));
5075:   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
5076:   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
5077:   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
5078:   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
5079:   for (p = pStart; p < pEnd; ++p) {
5080:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
5081:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

5083:     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
5084:     PetscCall(DMPlexGetCone(dmA, p, &cone));
5085:     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
5086:     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
5087:     PetscCall(DMPlexGetCone(dmB, p, &coneB));
5088:     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
5089:     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
5090:     for (c = 0; c < coneSize; ++c) {
5091:       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
5092:       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
5093:     }
5094:     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
5095:     PetscCall(DMPlexGetSupport(dmA, p, &support));
5096:     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
5097:     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
5098:     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
5099:     for (s = 0; s < supportSize; ++s) {
5100:       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
5101:     }
5102:   }
5103:   *equal = PETSC_TRUE;
5104:   PetscFunctionReturn(PETSC_SUCCESS);
5105: }

5107: /*@C
5108:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

5110:   Not Collective

5112:   Input Parameters:
5113: + dm         - The `DMPLEX`
5114: . cellDim    - The cell dimension
5115: - numCorners - The number of vertices on a cell

5117:   Output Parameter:
5118: . numFaceVertices - The number of vertices on a face

5120:   Level: developer

5122:   Note:
5123:   Of course this can only work for a restricted set of symmetric shapes

5125: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
5126: @*/
5127: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5128: {
5129:   MPI_Comm comm;

5131:   PetscFunctionBegin;
5132:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5133:   PetscAssertPointer(numFaceVertices, 4);
5134:   switch (cellDim) {
5135:   case 0:
5136:     *numFaceVertices = 0;
5137:     break;
5138:   case 1:
5139:     *numFaceVertices = 1;
5140:     break;
5141:   case 2:
5142:     switch (numCorners) {
5143:     case 3:                 /* triangle */
5144:       *numFaceVertices = 2; /* Edge has 2 vertices */
5145:       break;
5146:     case 4:                 /* quadrilateral */
5147:       *numFaceVertices = 2; /* Edge has 2 vertices */
5148:       break;
5149:     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
5150:       *numFaceVertices = 3; /* Edge has 3 vertices */
5151:       break;
5152:     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
5153:       *numFaceVertices = 3; /* Edge has 3 vertices */
5154:       break;
5155:     default:
5156:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5157:     }
5158:     break;
5159:   case 3:
5160:     switch (numCorners) {
5161:     case 4:                 /* tetradehdron */
5162:       *numFaceVertices = 3; /* Face has 3 vertices */
5163:       break;
5164:     case 6:                 /* tet cohesive cells */
5165:       *numFaceVertices = 4; /* Face has 4 vertices */
5166:       break;
5167:     case 8:                 /* hexahedron */
5168:       *numFaceVertices = 4; /* Face has 4 vertices */
5169:       break;
5170:     case 9:                 /* tet cohesive Lagrange cells */
5171:       *numFaceVertices = 6; /* Face has 6 vertices */
5172:       break;
5173:     case 10:                /* quadratic tetrahedron */
5174:       *numFaceVertices = 6; /* Face has 6 vertices */
5175:       break;
5176:     case 12:                /* hex cohesive Lagrange cells */
5177:       *numFaceVertices = 6; /* Face has 6 vertices */
5178:       break;
5179:     case 18:                /* quadratic tet cohesive Lagrange cells */
5180:       *numFaceVertices = 6; /* Face has 6 vertices */
5181:       break;
5182:     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
5183:       *numFaceVertices = 9; /* Face has 9 vertices */
5184:       break;
5185:     default:
5186:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5187:     }
5188:     break;
5189:   default:
5190:     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5191:   }
5192:   PetscFunctionReturn(PETSC_SUCCESS);
5193: }

5195: /*@
5196:   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point

5198:   Not Collective

5200:   Input Parameter:
5201: . dm - The `DMPLEX` object

5203:   Output Parameter:
5204: . depthLabel - The `DMLabel` recording point depth

5206:   Level: developer

5208: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5209: @*/
5210: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5211: {
5212:   PetscFunctionBegin;
5214:   PetscAssertPointer(depthLabel, 2);
5215:   *depthLabel = dm->depthLabel;
5216:   PetscFunctionReturn(PETSC_SUCCESS);
5217: }

5219: /*@
5220:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

5222:   Not Collective

5224:   Input Parameter:
5225: . dm - The `DMPLEX` object

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

5230:   Level: developer

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

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

5237:   An empty mesh gives -1.

5239: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5240: @*/
5241: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5242: {
5243:   DM_Plex *mesh = (DM_Plex *)dm->data;
5244:   DMLabel  label;
5245:   PetscInt d = 0;

5247:   PetscFunctionBegin;
5249:   PetscAssertPointer(depth, 2);
5250:   if (mesh->tr) {
5251:     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
5252:   } else {
5253:     PetscCall(DMPlexGetDepthLabel(dm, &label));
5254:     if (label) PetscCall(DMLabelGetNumValues(label, &d));
5255:     *depth = d - 1;
5256:   }
5257:   PetscFunctionReturn(PETSC_SUCCESS);
5258: }

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

5263:   Not Collective

5265:   Input Parameters:
5266: + dm    - The `DMPLEX` object
5267: - depth - The requested depth

5269:   Output Parameters:
5270: + start - The first point at this `depth`
5271: - end   - One beyond the last point at this `depth`

5273:   Level: developer

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

5280: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5281: @*/
5282: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5283: {
5284:   DM_Plex *mesh = (DM_Plex *)dm->data;
5285:   DMLabel  label;
5286:   PetscInt pStart, pEnd;

5288:   PetscFunctionBegin;
5290:   if (start) {
5291:     PetscAssertPointer(start, 3);
5292:     *start = 0;
5293:   }
5294:   if (end) {
5295:     PetscAssertPointer(end, 4);
5296:     *end = 0;
5297:   }
5298:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5299:   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5300:   if (depth < 0) {
5301:     if (start) *start = pStart;
5302:     if (end) *end = pEnd;
5303:     PetscFunctionReturn(PETSC_SUCCESS);
5304:   }
5305:   if (mesh->tr) {
5306:     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
5307:   } else {
5308:     PetscCall(DMPlexGetDepthLabel(dm, &label));
5309:     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5310:     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
5311:   }
5312:   PetscFunctionReturn(PETSC_SUCCESS);
5313: }

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

5318:   Not Collective

5320:   Input Parameters:
5321: + dm     - The `DMPLEX` object
5322: - height - The requested height

5324:   Output Parameters:
5325: + start - The first point at this `height`
5326: - end   - One beyond the last point at this `height`

5328:   Level: developer

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

5335: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5336: @*/
5337: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5338: {
5339:   DMLabel  label;
5340:   PetscInt depth, pStart, pEnd;

5342:   PetscFunctionBegin;
5344:   if (start) {
5345:     PetscAssertPointer(start, 3);
5346:     *start = 0;
5347:   }
5348:   if (end) {
5349:     PetscAssertPointer(end, 4);
5350:     *end = 0;
5351:   }
5352:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5353:   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5354:   if (height < 0) {
5355:     if (start) *start = pStart;
5356:     if (end) *end = pEnd;
5357:     PetscFunctionReturn(PETSC_SUCCESS);
5358:   }
5359:   PetscCall(DMPlexGetDepthLabel(dm, &label));
5360:   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
5361:   else PetscCall(DMGetDimension(dm, &depth));
5362:   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
5363:   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
5364:   PetscFunctionReturn(PETSC_SUCCESS);
5365: }

5367: /*@
5368:   DMPlexGetPointDepth - Get the `depth` of a given point

5370:   Not Collective

5372:   Input Parameters:
5373: + dm    - The `DMPLEX` object
5374: - point - The point

5376:   Output Parameter:
5377: . depth - The depth of the `point`

5379:   Level: intermediate

5381: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5382: @*/
5383: PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5384: {
5385:   PetscFunctionBegin;
5387:   PetscAssertPointer(depth, 3);
5388:   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
5389:   PetscFunctionReturn(PETSC_SUCCESS);
5390: }

5392: /*@
5393:   DMPlexGetPointHeight - Get the `height` of a given point

5395:   Not Collective

5397:   Input Parameters:
5398: + dm    - The `DMPLEX` object
5399: - point - The point

5401:   Output Parameter:
5402: . height - The height of the `point`

5404:   Level: intermediate

5406: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
5407: @*/
5408: PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5409: {
5410:   PetscInt n, pDepth;

5412:   PetscFunctionBegin;
5414:   PetscAssertPointer(height, 3);
5415:   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
5416:   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
5417:   *height = n - 1 - pDepth; /* DAG depth is n-1 */
5418:   PetscFunctionReturn(PETSC_SUCCESS);
5419: }

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

5424:   Not Collective

5426:   Input Parameter:
5427: . dm - The `DMPLEX` object

5429:   Output Parameter:
5430: . celltypeLabel - The `DMLabel` recording cell polytope type

5432:   Level: developer

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

5438: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5439: @*/
5440: PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5441: {
5442:   PetscFunctionBegin;
5444:   PetscAssertPointer(celltypeLabel, 2);
5445:   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5446:   *celltypeLabel = dm->celltypeLabel;
5447:   PetscFunctionReturn(PETSC_SUCCESS);
5448: }

5450: /*@
5451:   DMPlexGetCellType - Get the polytope type of a given cell

5453:   Not Collective

5455:   Input Parameters:
5456: + dm   - The `DMPLEX` object
5457: - cell - The cell

5459:   Output Parameter:
5460: . celltype - The polytope type of the cell

5462:   Level: intermediate

5464: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5465: @*/
5466: PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5467: {
5468:   DM_Plex *mesh = (DM_Plex *)dm->data;
5469:   DMLabel  label;
5470:   PetscInt ct;

5472:   PetscFunctionBegin;
5474:   PetscAssertPointer(celltype, 3);
5475:   if (mesh->tr) {
5476:     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
5477:   } else {
5478:     PetscInt pStart, pEnd;

5480:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
5481:     if (!mesh->cellTypes) { /* XXX remove? optimize? */
5482:       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5483:       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5484:       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5485:       for (PetscInt p = pStart; p < pEnd; p++) {
5486:         PetscCall(DMLabelGetValue(label, p, &ct));
5487:         mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
5488:       }
5489:     }
5490:     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
5491:     if (PetscDefined(USE_DEBUG)) {
5492:       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5493:       PetscCall(DMLabelGetValue(label, cell, &ct));
5494:       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5495:       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
5496:     }
5497:   }
5498:   PetscFunctionReturn(PETSC_SUCCESS);
5499: }

5501: /*@
5502:   DMPlexSetCellType - Set the polytope type of a given cell

5504:   Not Collective

5506:   Input Parameters:
5507: + dm       - The `DMPLEX` object
5508: . cell     - The cell
5509: - celltype - The polytope type of the cell

5511:   Level: advanced

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

5519: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5520: @*/
5521: PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5522: {
5523:   DM_Plex *mesh = (DM_Plex *)dm->data;
5524:   DMLabel  label;
5525:   PetscInt pStart, pEnd;

5527:   PetscFunctionBegin;
5529:   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
5530:   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5531:   PetscCall(DMLabelSetValue(label, cell, celltype));
5532:   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5533:   mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
5534:   PetscFunctionReturn(PETSC_SUCCESS);
5535: }

5537: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5538: {
5539:   PetscSection section;
5540:   PetscInt     maxHeight;
5541:   const char  *prefix;

5543:   PetscFunctionBegin;
5544:   PetscCall(DMClone(dm, cdm));
5545:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5546:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5547:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
5548:   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
5549:   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
5550:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
5551:   PetscCall(DMSetLocalSection(*cdm, section));
5552:   PetscCall(PetscSectionDestroy(&section));

5554:   PetscCall(DMSetNumFields(*cdm, 1));
5555:   PetscCall(DMCreateDS(*cdm));
5556:   (*cdm)->cloneOpts = PETSC_TRUE;
5557:   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
5558:   PetscFunctionReturn(PETSC_SUCCESS);
5559: }

5561: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5562: {
5563:   Vec coordsLocal, cellCoordsLocal;
5564:   DM  coordsDM, cellCoordsDM;

5566:   PetscFunctionBegin;
5567:   *field = NULL;
5568:   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
5569:   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
5570:   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
5571:   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5572:   if (coordsLocal && coordsDM) {
5573:     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
5574:     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5575:   }
5576:   PetscFunctionReturn(PETSC_SUCCESS);
5577: }

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

5582:   Not Collective

5584:   Input Parameter:
5585: . dm - The `DMPLEX` object

5587:   Output Parameter:
5588: . section - The `PetscSection` object

5590:   Level: developer

5592: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
5593: @*/
5594: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5595: {
5596:   DM_Plex *mesh = (DM_Plex *)dm->data;

5598:   PetscFunctionBegin;
5600:   if (section) *section = mesh->coneSection;
5601:   PetscFunctionReturn(PETSC_SUCCESS);
5602: }

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

5607:   Not Collective

5609:   Input Parameter:
5610: . dm - The `DMPLEX` object

5612:   Output Parameter:
5613: . section - The `PetscSection` object

5615:   Level: developer

5617: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
5618: @*/
5619: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5620: {
5621:   DM_Plex *mesh = (DM_Plex *)dm->data;

5623:   PetscFunctionBegin;
5625:   if (section) *section = mesh->supportSection;
5626:   PetscFunctionReturn(PETSC_SUCCESS);
5627: }

5629: /*@C
5630:   DMPlexGetCones - Return cone data

5632:   Not Collective

5634:   Input Parameter:
5635: . dm - The `DMPLEX` object

5637:   Output Parameter:
5638: . cones - The cone for each point

5640:   Level: developer

5642: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
5643: @*/
5644: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5645: {
5646:   DM_Plex *mesh = (DM_Plex *)dm->data;

5648:   PetscFunctionBegin;
5650:   if (cones) *cones = mesh->cones;
5651:   PetscFunctionReturn(PETSC_SUCCESS);
5652: }

5654: /*@C
5655:   DMPlexGetConeOrientations - Return cone orientation data

5657:   Not Collective

5659:   Input Parameter:
5660: . dm - The `DMPLEX` object

5662:   Output Parameter:
5663: . coneOrientations - The array of cone orientations for all points

5665:   Level: developer

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

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

5672: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
5673: @*/
5674: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5675: {
5676:   DM_Plex *mesh = (DM_Plex *)dm->data;

5678:   PetscFunctionBegin;
5680:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5681:   PetscFunctionReturn(PETSC_SUCCESS);
5682: }

5684: /******************************** FEM Support **********************************/

5686: PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5687: {
5688:   PetscInt depth;

5690:   PetscFunctionBegin;
5691:   PetscCall(DMPlexGetDepth(plex, &depth));
5692:   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5693:   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5694:   PetscFunctionReturn(PETSC_SUCCESS);
5695: }

5697: PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
5698: {
5699:   PetscInt depth;

5701:   PetscFunctionBegin;
5702:   PetscCall(DMPlexGetDepth(plex, &depth));
5703:   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
5704:   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
5705:   PetscFunctionReturn(PETSC_SUCCESS);
5706: }

5708: /*
5709:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5710:  representing a line in the section.
5711: */
5712: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5713: {
5714:   PetscObject  obj;
5715:   PetscClassId id;
5716:   PetscFE      fe = NULL;

5718:   PetscFunctionBeginHot;
5719:   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5720:   PetscCall(DMGetField(dm, field, NULL, &obj));
5721:   PetscCall(PetscObjectGetClassId(obj, &id));
5722:   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;

5724:   if (!fe) {
5725:     /* Assume the full interpolated mesh is in the chart; lines in particular */
5726:     /* An order k SEM disc has k-1 dofs on an edge */
5727:     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
5728:     *k = *k / *Nc + 1;
5729:   } else {
5730:     PetscInt       dual_space_size, dim;
5731:     PetscDualSpace dsp;

5733:     PetscCall(DMGetDimension(dm, &dim));
5734:     PetscCall(PetscFEGetDualSpace(fe, &dsp));
5735:     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5736:     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
5737:     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
5738:     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
5739:   }
5740:   PetscFunctionReturn(PETSC_SUCCESS);
5741: }

5743: static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
5744: {
5745:   PetscFunctionBeginHot;
5746:   if (tensor) {
5747:     *dof = PetscPowInt(k + 1, dim);
5748:   } else {
5749:     switch (dim) {
5750:     case 1:
5751:       *dof = k + 1;
5752:       break;
5753:     case 2:
5754:       *dof = ((k + 1) * (k + 2)) / 2;
5755:       break;
5756:     case 3:
5757:       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
5758:       break;
5759:     default:
5760:       *dof = 0;
5761:     }
5762:   }
5763:   PetscFunctionReturn(PETSC_SUCCESS);
5764: }

5766: /*@

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

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

5777:   Example:
5778:   A typical interpolated single-quad mesh might order points as
5779: .vb
5780:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

5782:   v4 -- e6 -- v3
5783:   |           |
5784:   e7    c0    e8
5785:   |           |
5786:   v1 -- e5 -- v2
5787: .ve

5789:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5790:   dofs in the order of points, e.g.,
5791: .vb
5792:     c0 -> [0,1,2,3]
5793:     v1 -> [4]
5794:     ...
5795:     e5 -> [8, 9]
5796: .ve

5798:   which corresponds to the dofs
5799: .vb
5800:     6   10  11  7
5801:     13  2   3   15
5802:     12  0   1   14
5803:     4   8   9   5
5804: .ve

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

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

5816:   Level: developer

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

5822:   This is required to run with libCEED.

5824: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5825: @*/
5826: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5827: {
5828:   DMLabel   label;
5829:   PetscInt  dim, depth = -1, eStart = -1, Nf;
5830:   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;

5832:   PetscFunctionBegin;
5833:   PetscCall(DMGetDimension(dm, &dim));
5834:   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5835:   if (point < 0) {
5836:     PetscInt sStart, sEnd;

5838:     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5839:     point = sEnd - sStart ? sStart : point;
5840:   }
5841:   PetscCall(DMPlexGetDepthLabel(dm, &label));
5842:   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
5843:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
5844:   if (depth == 1) {
5845:     eStart = point;
5846:   } else if (depth == dim) {
5847:     const PetscInt *cone;

5849:     PetscCall(DMPlexGetCone(dm, point, &cone));
5850:     if (dim == 2) eStart = cone[0];
5851:     else if (dim == 3) {
5852:       const PetscInt *cone2;
5853:       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5854:       eStart = cone2[0];
5855:     } 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);
5856:   } 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);

5858:   PetscCall(PetscSectionGetNumFields(section, &Nf));
5859:   for (PetscInt d = 1; d <= dim; d++) {
5860:     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5861:     PetscInt *perm;

5863:     for (f = 0; f < Nf; ++f) {
5864:       PetscInt dof;

5866:       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5867:       PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f);
5868:       if (!continuous && d < dim) continue;
5869:       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
5870:       size += dof * Nc;
5871:     }
5872:     PetscCall(PetscMalloc1(size, &perm));
5873:     for (f = 0; f < Nf; ++f) {
5874:       switch (d) {
5875:       case 1:
5876:         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5877:         if (!continuous && d < dim) continue;
5878:         /*
5879:          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5880:          We want              [ vtx0; edge of length k-1; vtx1 ]
5881:          */
5882:         if (continuous) {
5883:           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
5884:           for (i = 0; i < k - 1; i++)
5885:             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5886:           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5887:           foffset = offset;
5888:         } else {
5889:           PetscInt dof;

5891:           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
5892:           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
5893:           foffset = offset;
5894:         }
5895:         break;
5896:       case 2:
5897:         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5898:         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5899:         if (!continuous && d < dim) continue;
5900:         /* The SEM order is

5902:          v_lb, {e_b}, v_rb,
5903:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5904:          v_lt, reverse {e_t}, v_rt
5905:          */
5906:         if (continuous) {
5907:           const PetscInt of   = 0;
5908:           const PetscInt oeb  = of + PetscSqr(k - 1);
5909:           const PetscInt oer  = oeb + (k - 1);
5910:           const PetscInt oet  = oer + (k - 1);
5911:           const PetscInt oel  = oet + (k - 1);
5912:           const PetscInt ovlb = oel + (k - 1);
5913:           const PetscInt ovrb = ovlb + 1;
5914:           const PetscInt ovrt = ovrb + 1;
5915:           const PetscInt ovlt = ovrt + 1;
5916:           PetscInt       o;

5918:           /* bottom */
5919:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
5920:           for (o = oeb; o < oer; ++o)
5921:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5922:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
5923:           /* middle */
5924:           for (i = 0; i < k - 1; ++i) {
5925:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
5926:             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
5927:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5928:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
5929:           }
5930:           /* top */
5931:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
5932:           for (o = oel - 1; o >= oet; --o)
5933:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5934:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
5935:           foffset = offset;
5936:         } else {
5937:           PetscInt dof;

5939:           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
5940:           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
5941:           foffset = offset;
5942:         }
5943:         break;
5944:       case 3:
5945:         /* The original hex closure is

5947:          {c,
5948:          f_b, f_t, f_f, f_b, f_r, f_l,
5949:          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5950:          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5951:          */
5952:         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5953:         if (!continuous && d < dim) continue;
5954:         /* The SEM order is
5955:          Bottom Slice
5956:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5957:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5958:          v_blb, {e_bb}, v_brb,

5960:          Middle Slice (j)
5961:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5962:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5963:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

5965:          Top Slice
5966:          v_tlf, {e_tf}, v_trf,
5967:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5968:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5969:          */
5970:         if (continuous) {
5971:           const PetscInt oc    = 0;
5972:           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
5973:           const PetscInt oft   = ofb + PetscSqr(k - 1);
5974:           const PetscInt off   = oft + PetscSqr(k - 1);
5975:           const PetscInt ofk   = off + PetscSqr(k - 1);
5976:           const PetscInt ofr   = ofk + PetscSqr(k - 1);
5977:           const PetscInt ofl   = ofr + PetscSqr(k - 1);
5978:           const PetscInt oebl  = ofl + PetscSqr(k - 1);
5979:           const PetscInt oebb  = oebl + (k - 1);
5980:           const PetscInt oebr  = oebb + (k - 1);
5981:           const PetscInt oebf  = oebr + (k - 1);
5982:           const PetscInt oetf  = oebf + (k - 1);
5983:           const PetscInt oetr  = oetf + (k - 1);
5984:           const PetscInt oetb  = oetr + (k - 1);
5985:           const PetscInt oetl  = oetb + (k - 1);
5986:           const PetscInt oerf  = oetl + (k - 1);
5987:           const PetscInt oelf  = oerf + (k - 1);
5988:           const PetscInt oelb  = oelf + (k - 1);
5989:           const PetscInt oerb  = oelb + (k - 1);
5990:           const PetscInt ovblf = oerb + (k - 1);
5991:           const PetscInt ovblb = ovblf + 1;
5992:           const PetscInt ovbrb = ovblb + 1;
5993:           const PetscInt ovbrf = ovbrb + 1;
5994:           const PetscInt ovtlf = ovbrf + 1;
5995:           const PetscInt ovtrf = ovtlf + 1;
5996:           const PetscInt ovtrb = ovtrf + 1;
5997:           const PetscInt ovtlb = ovtrb + 1;
5998:           PetscInt       o, n;

6000:           /* Bottom Slice */
6001:           /*   bottom */
6002:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
6003:           for (o = oetf - 1; o >= oebf; --o)
6004:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6005:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
6006:           /*   middle */
6007:           for (i = 0; i < k - 1; ++i) {
6008:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
6009:             for (n = 0; n < k - 1; ++n) {
6010:               o = ofb + n * (k - 1) + i;
6011:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6012:             }
6013:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
6014:           }
6015:           /*   top */
6016:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
6017:           for (o = oebb; o < oebr; ++o)
6018:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6019:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;

6021:           /* Middle Slice */
6022:           for (j = 0; j < k - 1; ++j) {
6023:             /*   bottom */
6024:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
6025:             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
6026:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6027:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
6028:             /*   middle */
6029:             for (i = 0; i < k - 1; ++i) {
6030:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
6031:               for (n = 0; n < k - 1; ++n)
6032:                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
6033:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
6034:             }
6035:             /*   top */
6036:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
6037:             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
6038:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6039:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
6040:           }

6042:           /* Top Slice */
6043:           /*   bottom */
6044:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
6045:           for (o = oetf; o < oetr; ++o)
6046:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6047:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
6048:           /*   middle */
6049:           for (i = 0; i < k - 1; ++i) {
6050:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
6051:             for (n = 0; n < k - 1; ++n)
6052:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
6053:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
6054:           }
6055:           /*   top */
6056:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
6057:           for (o = oetl - 1; o >= oetb; --o)
6058:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6059:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;

6061:           foffset = offset;
6062:         } else {
6063:           PetscInt dof;

6065:           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
6066:           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
6067:           foffset = offset;
6068:         }
6069:         break;
6070:       default:
6071:         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
6072:       }
6073:     }
6074:     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
6075:     /* Check permutation */
6076:     {
6077:       PetscInt *check;

6079:       PetscCall(PetscMalloc1(size, &check));
6080:       for (i = 0; i < size; ++i) {
6081:         check[i] = -1;
6082:         PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);
6083:       }
6084:       for (i = 0; i < size; ++i) check[perm[i]] = i;
6085:       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
6086:       PetscCall(PetscFree(check));
6087:     }
6088:     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6089:     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6090:       PetscInt *loc_perm;
6091:       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6092:       for (PetscInt i = 0; i < size; i++) {
6093:         loc_perm[i]        = perm[i];
6094:         loc_perm[size + i] = size + perm[i];
6095:       }
6096:       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6097:     }
6098:   }
6099:   PetscFunctionReturn(PETSC_SUCCESS);
6100: }

6102: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6103: {
6104:   PetscDS  prob;
6105:   PetscInt depth, Nf, h;
6106:   DMLabel  label;

6108:   PetscFunctionBeginHot;
6109:   PetscCall(DMGetDS(dm, &prob));
6110:   Nf      = prob->Nf;
6111:   label   = dm->depthLabel;
6112:   *dspace = NULL;
6113:   if (field < Nf) {
6114:     PetscObject disc = prob->disc[field];

6116:     if (disc->classid == PETSCFE_CLASSID) {
6117:       PetscDualSpace dsp;

6119:       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
6120:       PetscCall(DMLabelGetNumValues(label, &depth));
6121:       PetscCall(DMLabelGetValue(label, point, &h));
6122:       h = depth - 1 - h;
6123:       if (h) {
6124:         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6125:       } else {
6126:         *dspace = dsp;
6127:       }
6128:     }
6129:   }
6130:   PetscFunctionReturn(PETSC_SUCCESS);
6131: }

6133: static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6134: {
6135:   PetscScalar       *array;
6136:   const PetscScalar *vArray;
6137:   const PetscInt    *cone, *coneO;
6138:   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;

6140:   PetscFunctionBeginHot;
6141:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6142:   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6143:   PetscCall(DMPlexGetCone(dm, point, &cone));
6144:   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6145:   if (!values || !*values) {
6146:     if ((point >= pStart) && (point < pEnd)) {
6147:       PetscInt dof;

6149:       PetscCall(PetscSectionGetDof(section, point, &dof));
6150:       size += dof;
6151:     }
6152:     for (p = 0; p < numPoints; ++p) {
6153:       const PetscInt cp = cone[p];
6154:       PetscInt       dof;

6156:       if ((cp < pStart) || (cp >= pEnd)) continue;
6157:       PetscCall(PetscSectionGetDof(section, cp, &dof));
6158:       size += dof;
6159:     }
6160:     if (!values) {
6161:       if (csize) *csize = size;
6162:       PetscFunctionReturn(PETSC_SUCCESS);
6163:     }
6164:     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6165:   } else {
6166:     array = *values;
6167:   }
6168:   size = 0;
6169:   PetscCall(VecGetArrayRead(v, &vArray));
6170:   if ((point >= pStart) && (point < pEnd)) {
6171:     PetscInt           dof, off, d;
6172:     const PetscScalar *varr;

6174:     PetscCall(PetscSectionGetDof(section, point, &dof));
6175:     PetscCall(PetscSectionGetOffset(section, point, &off));
6176:     varr = PetscSafePointerPlusOffset(vArray, off);
6177:     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
6178:     size += dof;
6179:   }
6180:   for (p = 0; p < numPoints; ++p) {
6181:     const PetscInt     cp = cone[p];
6182:     PetscInt           o  = coneO[p];
6183:     PetscInt           dof, off, d;
6184:     const PetscScalar *varr;

6186:     if ((cp < pStart) || (cp >= pEnd)) continue;
6187:     PetscCall(PetscSectionGetDof(section, cp, &dof));
6188:     PetscCall(PetscSectionGetOffset(section, cp, &off));
6189:     varr = PetscSafePointerPlusOffset(vArray, off);
6190:     if (o >= 0) {
6191:       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
6192:     } else {
6193:       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
6194:     }
6195:     size += dof;
6196:   }
6197:   PetscCall(VecRestoreArrayRead(v, &vArray));
6198:   if (!*values) {
6199:     if (csize) *csize = size;
6200:     *values = array;
6201:   } else {
6202:     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6203:     *csize = size;
6204:   }
6205:   PetscFunctionReturn(PETSC_SUCCESS);
6206: }

6208: /* Compress out points not in the section */
6209: static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6210: {
6211:   const PetscInt np = *numPoints;
6212:   PetscInt       pStart, pEnd, p, q;

6214:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6215:   for (p = 0, q = 0; p < np; ++p) {
6216:     const PetscInt r = points[p * 2];
6217:     if ((r >= pStart) && (r < pEnd)) {
6218:       points[q * 2]     = r;
6219:       points[q * 2 + 1] = points[p * 2 + 1];
6220:       ++q;
6221:     }
6222:   }
6223:   *numPoints = q;
6224:   return PETSC_SUCCESS;
6225: }

6227: /* Compressed closure does not apply closure permutation */
6228: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6229: {
6230:   const PetscInt *cla = NULL;
6231:   PetscInt        np, *pts = NULL;

6233:   PetscFunctionBeginHot;
6234:   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
6235:   if (!ornt && *clPoints) {
6236:     PetscInt dof, off;

6238:     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
6239:     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
6240:     PetscCall(ISGetIndices(*clPoints, &cla));
6241:     np  = dof / 2;
6242:     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
6243:   } else {
6244:     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
6245:     PetscCall(CompressPoints_Private(section, &np, pts));
6246:   }
6247:   *numPoints = np;
6248:   *points    = pts;
6249:   *clp       = cla;
6250:   PetscFunctionReturn(PETSC_SUCCESS);
6251: }

6253: PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6254: {
6255:   PetscFunctionBeginHot;
6256:   if (!*clPoints) {
6257:     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6258:   } else {
6259:     PetscCall(ISRestoreIndices(*clPoints, clp));
6260:   }
6261:   *numPoints = 0;
6262:   *points    = NULL;
6263:   *clSec     = NULL;
6264:   *clPoints  = NULL;
6265:   *clp       = NULL;
6266:   PetscFunctionReturn(PETSC_SUCCESS);
6267: }

6269: static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
6270: {
6271:   PetscInt            offset = 0, p;
6272:   const PetscInt    **perms  = NULL;
6273:   const PetscScalar **flips  = NULL;

6275:   PetscFunctionBeginHot;
6276:   *size = 0;
6277:   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6278:   for (p = 0; p < numPoints; p++) {
6279:     const PetscInt     point = points[2 * p];
6280:     const PetscInt    *perm  = perms ? perms[p] : NULL;
6281:     const PetscScalar *flip  = flips ? flips[p] : NULL;
6282:     PetscInt           dof, off, d;
6283:     const PetscScalar *varr;

6285:     PetscCall(PetscSectionGetDof(section, point, &dof));
6286:     PetscCall(PetscSectionGetOffset(section, point, &off));
6287:     varr = PetscSafePointerPlusOffset(vArray, off);
6288:     if (clperm) {
6289:       if (perm) {
6290:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
6291:       } else {
6292:         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
6293:       }
6294:       if (flip) {
6295:         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
6296:       }
6297:     } else {
6298:       if (perm) {
6299:         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
6300:       } else {
6301:         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
6302:       }
6303:       if (flip) {
6304:         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
6305:       }
6306:     }
6307:     offset += dof;
6308:   }
6309:   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6310:   *size = offset;
6311:   PetscFunctionReturn(PETSC_SUCCESS);
6312: }

6314: 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[])
6315: {
6316:   PetscInt offset = 0, f;

6318:   PetscFunctionBeginHot;
6319:   *size = 0;
6320:   for (f = 0; f < numFields; ++f) {
6321:     PetscInt            p;
6322:     const PetscInt    **perms = NULL;
6323:     const PetscScalar **flips = NULL;

6325:     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6326:     for (p = 0; p < numPoints; p++) {
6327:       const PetscInt     point = points[2 * p];
6328:       PetscInt           fdof, foff, b;
6329:       const PetscScalar *varr;
6330:       const PetscInt    *perm = perms ? perms[p] : NULL;
6331:       const PetscScalar *flip = flips ? flips[p] : NULL;

6333:       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6334:       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6335:       varr = &vArray[foff];
6336:       if (clperm) {
6337:         if (perm) {
6338:           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
6339:         } else {
6340:           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
6341:         }
6342:         if (flip) {
6343:           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
6344:         }
6345:       } else {
6346:         if (perm) {
6347:           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
6348:         } else {
6349:           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
6350:         }
6351:         if (flip) {
6352:           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
6353:         }
6354:       }
6355:       offset += fdof;
6356:     }
6357:     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6358:   }
6359:   *size = offset;
6360:   PetscFunctionReturn(PETSC_SUCCESS);
6361: }

6363: PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
6364: {
6365:   PetscSection    clSection;
6366:   IS              clPoints;
6367:   PetscInt       *points = NULL;
6368:   const PetscInt *clp, *perm = NULL;
6369:   PetscInt        depth, numFields, numPoints, asize;

6371:   PetscFunctionBeginHot;
6373:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6376:   PetscCall(DMPlexGetDepth(dm, &depth));
6377:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6378:   if (depth == 1 && numFields < 2) {
6379:     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6380:     PetscFunctionReturn(PETSC_SUCCESS);
6381:   }
6382:   /* Get points */
6383:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
6384:   /* Get sizes */
6385:   asize = 0;
6386:   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
6387:     PetscInt dof;
6388:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
6389:     asize += dof;
6390:   }
6391:   if (values) {
6392:     const PetscScalar *vArray;
6393:     PetscInt           size;

6395:     if (*values) {
6396:       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);
6397:     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6398:     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
6399:     PetscCall(VecGetArrayRead(v, &vArray));
6400:     /* Get values */
6401:     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
6402:     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
6403:     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
6404:     /* Cleanup array */
6405:     PetscCall(VecRestoreArrayRead(v, &vArray));
6406:   }
6407:   if (csize) *csize = asize;
6408:   /* Cleanup points */
6409:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6410:   PetscFunctionReturn(PETSC_SUCCESS);
6411: }

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

6416:   Not collective

6418:   Input Parameters:
6419: + dm      - The `DM`
6420: . section - The section describing the layout in `v`, or `NULL` to use the default section
6421: . v       - The local vector
6422: - point   - The point in the `DM`

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

6429:   Level: intermediate

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

6436:   A typical use could be
6437: .vb
6438:    values = NULL;
6439:    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6440:    for (cl = 0; cl < clSize; ++cl) {
6441:      <Compute on closure>
6442:    }
6443:    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6444: .ve
6445:   or
6446: .vb
6447:    PetscMalloc1(clMaxSize, &values);
6448:    for (p = pStart; p < pEnd; ++p) {
6449:      clSize = clMaxSize;
6450:      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6451:      for (cl = 0; cl < clSize; ++cl) {
6452:        <Compute on closure>
6453:      }
6454:    }
6455:    PetscFree(values);
6456: .ve

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

6461: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6462: @*/
6463: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6464: {
6465:   PetscFunctionBeginHot;
6466:   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
6467:   PetscFunctionReturn(PETSC_SUCCESS);
6468: }

6470: PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6471: {
6472:   DMLabel            depthLabel;
6473:   PetscSection       clSection;
6474:   IS                 clPoints;
6475:   PetscScalar       *array;
6476:   const PetscScalar *vArray;
6477:   PetscInt          *points = NULL;
6478:   const PetscInt    *clp, *perm = NULL;
6479:   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;

6481:   PetscFunctionBeginHot;
6483:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6486:   PetscCall(DMPlexGetDepth(dm, &mdepth));
6487:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
6488:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6489:   if (mdepth == 1 && numFields < 2) {
6490:     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6491:     PetscFunctionReturn(PETSC_SUCCESS);
6492:   }
6493:   /* Get points */
6494:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6495:   for (clsize = 0, p = 0; p < Np; p++) {
6496:     PetscInt dof;
6497:     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6498:     clsize += dof;
6499:   }
6500:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6501:   /* Filter points */
6502:   for (p = 0; p < numPoints * 2; p += 2) {
6503:     PetscInt dep;

6505:     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6506:     if (dep != depth) continue;
6507:     points[Np * 2 + 0] = points[p];
6508:     points[Np * 2 + 1] = points[p + 1];
6509:     ++Np;
6510:   }
6511:   /* Get array */
6512:   if (!values || !*values) {
6513:     PetscInt asize = 0, dof;

6515:     for (p = 0; p < Np * 2; p += 2) {
6516:       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6517:       asize += dof;
6518:     }
6519:     if (!values) {
6520:       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6521:       if (csize) *csize = asize;
6522:       PetscFunctionReturn(PETSC_SUCCESS);
6523:     }
6524:     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6525:   } else {
6526:     array = *values;
6527:   }
6528:   PetscCall(VecGetArrayRead(v, &vArray));
6529:   /* Get values */
6530:   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
6531:   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6532:   /* Cleanup points */
6533:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6534:   /* Cleanup array */
6535:   PetscCall(VecRestoreArrayRead(v, &vArray));
6536:   if (!*values) {
6537:     if (csize) *csize = size;
6538:     *values = array;
6539:   } else {
6540:     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6541:     *csize = size;
6542:   }
6543:   PetscFunctionReturn(PETSC_SUCCESS);
6544: }

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

6549:   Not collective

6551:   Input Parameters:
6552: + dm      - The `DM`
6553: . section - The section describing the layout in `v`, or `NULL` to use the default section
6554: . v       - The local vector
6555: . point   - The point in the `DM`
6556: . csize   - The number of values in the closure, or `NULL`
6557: - values  - The array of values, which is a borrowed array and should not be freed

6559:   Level: intermediate

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

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

6567: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6568: @*/
6569: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6570: {
6571:   PetscInt size = 0;

6573:   PetscFunctionBegin;
6574:   /* Should work without recalculating size */
6575:   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6576:   *values = NULL;
6577:   PetscFunctionReturn(PETSC_SUCCESS);
6578: }

6580: static inline void add(PetscScalar *x, PetscScalar y)
6581: {
6582:   *x += y;
6583: }
6584: static inline void insert(PetscScalar *x, PetscScalar y)
6585: {
6586:   *x = y;
6587: }

6589: 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[])
6590: {
6591:   PetscInt        cdof;  /* The number of constraints on this point */
6592:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6593:   PetscScalar    *a;
6594:   PetscInt        off, cind = 0, k;

6596:   PetscFunctionBegin;
6597:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6598:   PetscCall(PetscSectionGetOffset(section, point, &off));
6599:   a = &array[off];
6600:   if (!cdof || setBC) {
6601:     if (clperm) {
6602:       if (perm) {
6603:         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6604:       } else {
6605:         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6606:       }
6607:     } else {
6608:       if (perm) {
6609:         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6610:       } else {
6611:         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6612:       }
6613:     }
6614:   } else {
6615:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6616:     if (clperm) {
6617:       if (perm) {
6618:         for (k = 0; k < dof; ++k) {
6619:           if ((cind < cdof) && (k == cdofs[cind])) {
6620:             ++cind;
6621:             continue;
6622:           }
6623:           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6624:         }
6625:       } else {
6626:         for (k = 0; k < dof; ++k) {
6627:           if ((cind < cdof) && (k == cdofs[cind])) {
6628:             ++cind;
6629:             continue;
6630:           }
6631:           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6632:         }
6633:       }
6634:     } else {
6635:       if (perm) {
6636:         for (k = 0; k < dof; ++k) {
6637:           if ((cind < cdof) && (k == cdofs[cind])) {
6638:             ++cind;
6639:             continue;
6640:           }
6641:           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6642:         }
6643:       } else {
6644:         for (k = 0; k < dof; ++k) {
6645:           if ((cind < cdof) && (k == cdofs[cind])) {
6646:             ++cind;
6647:             continue;
6648:           }
6649:           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6650:         }
6651:       }
6652:     }
6653:   }
6654:   PetscFunctionReturn(PETSC_SUCCESS);
6655: }

6657: 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[])
6658: {
6659:   PetscInt        cdof;  /* The number of constraints on this point */
6660:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6661:   PetscScalar    *a;
6662:   PetscInt        off, cind = 0, k;

6664:   PetscFunctionBegin;
6665:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6666:   PetscCall(PetscSectionGetOffset(section, point, &off));
6667:   a = &array[off];
6668:   if (cdof) {
6669:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6670:     if (clperm) {
6671:       if (perm) {
6672:         for (k = 0; k < dof; ++k) {
6673:           if ((cind < cdof) && (k == cdofs[cind])) {
6674:             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6675:             cind++;
6676:           }
6677:         }
6678:       } else {
6679:         for (k = 0; k < dof; ++k) {
6680:           if ((cind < cdof) && (k == cdofs[cind])) {
6681:             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6682:             cind++;
6683:           }
6684:         }
6685:       }
6686:     } else {
6687:       if (perm) {
6688:         for (k = 0; k < dof; ++k) {
6689:           if ((cind < cdof) && (k == cdofs[cind])) {
6690:             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6691:             cind++;
6692:           }
6693:         }
6694:       } else {
6695:         for (k = 0; k < dof; ++k) {
6696:           if ((cind < cdof) && (k == cdofs[cind])) {
6697:             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6698:             cind++;
6699:           }
6700:         }
6701:       }
6702:     }
6703:   }
6704:   PetscFunctionReturn(PETSC_SUCCESS);
6705: }

6707: 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[])
6708: {
6709:   PetscScalar    *a;
6710:   PetscInt        fdof, foff, fcdof, foffset = *offset;
6711:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6712:   PetscInt        cind = 0, b;

6714:   PetscFunctionBegin;
6715:   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6716:   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6717:   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6718:   a = &array[foff];
6719:   if (!fcdof || setBC) {
6720:     if (clperm) {
6721:       if (perm) {
6722:         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6723:       } else {
6724:         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6725:       }
6726:     } else {
6727:       if (perm) {
6728:         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6729:       } else {
6730:         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6731:       }
6732:     }
6733:   } else {
6734:     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6735:     if (clperm) {
6736:       if (perm) {
6737:         for (b = 0; b < fdof; b++) {
6738:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6739:             ++cind;
6740:             continue;
6741:           }
6742:           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6743:         }
6744:       } else {
6745:         for (b = 0; b < fdof; b++) {
6746:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6747:             ++cind;
6748:             continue;
6749:           }
6750:           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6751:         }
6752:       }
6753:     } else {
6754:       if (perm) {
6755:         for (b = 0; b < fdof; b++) {
6756:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6757:             ++cind;
6758:             continue;
6759:           }
6760:           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6761:         }
6762:       } else {
6763:         for (b = 0; b < fdof; b++) {
6764:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6765:             ++cind;
6766:             continue;
6767:           }
6768:           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6769:         }
6770:       }
6771:     }
6772:   }
6773:   *offset += fdof;
6774:   PetscFunctionReturn(PETSC_SUCCESS);
6775: }

6777: 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[])
6778: {
6779:   PetscScalar    *a;
6780:   PetscInt        fdof, foff, fcdof, foffset = *offset;
6781:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6782:   PetscInt        Nc, cind = 0, ncind = 0, b;
6783:   PetscBool       ncSet, fcSet;

6785:   PetscFunctionBegin;
6786:   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
6787:   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6788:   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6789:   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6790:   a = &array[foff];
6791:   if (fcdof) {
6792:     /* We just override fcdof and fcdofs with Ncc and comps */
6793:     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6794:     if (clperm) {
6795:       if (perm) {
6796:         if (comps) {
6797:           for (b = 0; b < fdof; b++) {
6798:             ncSet = fcSet = PETSC_FALSE;
6799:             if (b % Nc == comps[ncind]) {
6800:               ncind = (ncind + 1) % Ncc;
6801:               ncSet = PETSC_TRUE;
6802:             }
6803:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6804:               ++cind;
6805:               fcSet = PETSC_TRUE;
6806:             }
6807:             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6808:           }
6809:         } else {
6810:           for (b = 0; b < fdof; b++) {
6811:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6812:               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6813:               ++cind;
6814:             }
6815:           }
6816:         }
6817:       } else {
6818:         if (comps) {
6819:           for (b = 0; b < fdof; b++) {
6820:             ncSet = fcSet = PETSC_FALSE;
6821:             if (b % Nc == comps[ncind]) {
6822:               ncind = (ncind + 1) % Ncc;
6823:               ncSet = PETSC_TRUE;
6824:             }
6825:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6826:               ++cind;
6827:               fcSet = PETSC_TRUE;
6828:             }
6829:             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6830:           }
6831:         } else {
6832:           for (b = 0; b < fdof; b++) {
6833:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6834:               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6835:               ++cind;
6836:             }
6837:           }
6838:         }
6839:       }
6840:     } else {
6841:       if (perm) {
6842:         if (comps) {
6843:           for (b = 0; b < fdof; b++) {
6844:             ncSet = fcSet = PETSC_FALSE;
6845:             if (b % Nc == comps[ncind]) {
6846:               ncind = (ncind + 1) % Ncc;
6847:               ncSet = PETSC_TRUE;
6848:             }
6849:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6850:               ++cind;
6851:               fcSet = PETSC_TRUE;
6852:             }
6853:             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6854:           }
6855:         } else {
6856:           for (b = 0; b < fdof; b++) {
6857:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6858:               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6859:               ++cind;
6860:             }
6861:           }
6862:         }
6863:       } else {
6864:         if (comps) {
6865:           for (b = 0; b < fdof; b++) {
6866:             ncSet = fcSet = PETSC_FALSE;
6867:             if (b % Nc == comps[ncind]) {
6868:               ncind = (ncind + 1) % Ncc;
6869:               ncSet = PETSC_TRUE;
6870:             }
6871:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6872:               ++cind;
6873:               fcSet = PETSC_TRUE;
6874:             }
6875:             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6876:           }
6877:         } else {
6878:           for (b = 0; b < fdof; b++) {
6879:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6880:               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6881:               ++cind;
6882:             }
6883:           }
6884:         }
6885:       }
6886:     }
6887:   }
6888:   *offset += fdof;
6889:   PetscFunctionReturn(PETSC_SUCCESS);
6890: }

6892: static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6893: {
6894:   PetscScalar    *array;
6895:   const PetscInt *cone, *coneO;
6896:   PetscInt        pStart, pEnd, p, numPoints, off, dof;

6898:   PetscFunctionBeginHot;
6899:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6900:   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6901:   PetscCall(DMPlexGetCone(dm, point, &cone));
6902:   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6903:   PetscCall(VecGetArray(v, &array));
6904:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6905:     const PetscInt cp = !p ? point : cone[p - 1];
6906:     const PetscInt o  = !p ? 0 : coneO[p - 1];

6908:     if ((cp < pStart) || (cp >= pEnd)) {
6909:       dof = 0;
6910:       continue;
6911:     }
6912:     PetscCall(PetscSectionGetDof(section, cp, &dof));
6913:     /* ADD_VALUES */
6914:     {
6915:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6916:       PetscScalar    *a;
6917:       PetscInt        cdof, coff, cind = 0, k;

6919:       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
6920:       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6921:       a = &array[coff];
6922:       if (!cdof) {
6923:         if (o >= 0) {
6924:           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6925:         } else {
6926:           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6927:         }
6928:       } else {
6929:         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6930:         if (o >= 0) {
6931:           for (k = 0; k < dof; ++k) {
6932:             if ((cind < cdof) && (k == cdofs[cind])) {
6933:               ++cind;
6934:               continue;
6935:             }
6936:             a[k] += values[off + k];
6937:           }
6938:         } else {
6939:           for (k = 0; k < dof; ++k) {
6940:             if ((cind < cdof) && (k == cdofs[cind])) {
6941:               ++cind;
6942:               continue;
6943:             }
6944:             a[k] += values[off + dof - k - 1];
6945:           }
6946:         }
6947:       }
6948:     }
6949:   }
6950:   PetscCall(VecRestoreArray(v, &array));
6951:   PetscFunctionReturn(PETSC_SUCCESS);
6952: }

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

6957:   Not collective

6959:   Input Parameters:
6960: + dm      - The `DM`
6961: . section - The section describing the layout in `v`, or `NULL` to use the default section
6962: . v       - The local vector
6963: . point   - The point in the `DM`
6964: . values  - The array of values
6965: - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6966:          where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.

6968:   Level: intermediate

6970: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
6971: @*/
6972: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6973: {
6974:   PetscSection    clSection;
6975:   IS              clPoints;
6976:   PetscScalar    *array;
6977:   PetscInt       *points = NULL;
6978:   const PetscInt *clp, *clperm = NULL;
6979:   PetscInt        depth, numFields, numPoints, p, clsize;

6981:   PetscFunctionBeginHot;
6983:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6986:   PetscCall(DMPlexGetDepth(dm, &depth));
6987:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6988:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6989:     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
6990:     PetscFunctionReturn(PETSC_SUCCESS);
6991:   }
6992:   /* Get points */
6993:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6994:   for (clsize = 0, p = 0; p < numPoints; p++) {
6995:     PetscInt dof;
6996:     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6997:     clsize += dof;
6998:   }
6999:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7000:   /* Get array */
7001:   PetscCall(VecGetArray(v, &array));
7002:   /* Get values */
7003:   if (numFields > 0) {
7004:     PetscInt offset = 0, f;
7005:     for (f = 0; f < numFields; ++f) {
7006:       const PetscInt    **perms = NULL;
7007:       const PetscScalar **flips = NULL;

7009:       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7010:       switch (mode) {
7011:       case INSERT_VALUES:
7012:         for (p = 0; p < numPoints; p++) {
7013:           const PetscInt     point = points[2 * p];
7014:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7015:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7016:           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
7017:         }
7018:         break;
7019:       case INSERT_ALL_VALUES:
7020:         for (p = 0; p < numPoints; p++) {
7021:           const PetscInt     point = points[2 * p];
7022:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7023:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7024:           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
7025:         }
7026:         break;
7027:       case INSERT_BC_VALUES:
7028:         for (p = 0; p < numPoints; p++) {
7029:           const PetscInt     point = points[2 * p];
7030:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7031:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7032:           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
7033:         }
7034:         break;
7035:       case ADD_VALUES:
7036:         for (p = 0; p < numPoints; p++) {
7037:           const PetscInt     point = points[2 * p];
7038:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7039:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7040:           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
7041:         }
7042:         break;
7043:       case ADD_ALL_VALUES:
7044:         for (p = 0; p < numPoints; p++) {
7045:           const PetscInt     point = points[2 * p];
7046:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7047:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7048:           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
7049:         }
7050:         break;
7051:       case ADD_BC_VALUES:
7052:         for (p = 0; p < numPoints; p++) {
7053:           const PetscInt     point = points[2 * p];
7054:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7055:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7056:           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
7057:         }
7058:         break;
7059:       default:
7060:         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7061:       }
7062:       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7063:     }
7064:   } else {
7065:     PetscInt            dof, off;
7066:     const PetscInt    **perms = NULL;
7067:     const PetscScalar **flips = NULL;

7069:     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7070:     switch (mode) {
7071:     case INSERT_VALUES:
7072:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7073:         const PetscInt     point = points[2 * p];
7074:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7075:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7076:         PetscCall(PetscSectionGetDof(section, point, &dof));
7077:         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
7078:       }
7079:       break;
7080:     case INSERT_ALL_VALUES:
7081:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7082:         const PetscInt     point = points[2 * p];
7083:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7084:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7085:         PetscCall(PetscSectionGetDof(section, point, &dof));
7086:         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
7087:       }
7088:       break;
7089:     case INSERT_BC_VALUES:
7090:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7091:         const PetscInt     point = points[2 * p];
7092:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7093:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7094:         PetscCall(PetscSectionGetDof(section, point, &dof));
7095:         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
7096:       }
7097:       break;
7098:     case ADD_VALUES:
7099:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7100:         const PetscInt     point = points[2 * p];
7101:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7102:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7103:         PetscCall(PetscSectionGetDof(section, point, &dof));
7104:         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
7105:       }
7106:       break;
7107:     case ADD_ALL_VALUES:
7108:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7109:         const PetscInt     point = points[2 * p];
7110:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7111:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7112:         PetscCall(PetscSectionGetDof(section, point, &dof));
7113:         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
7114:       }
7115:       break;
7116:     case ADD_BC_VALUES:
7117:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7118:         const PetscInt     point = points[2 * p];
7119:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7120:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7121:         PetscCall(PetscSectionGetDof(section, point, &dof));
7122:         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
7123:       }
7124:       break;
7125:     default:
7126:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7127:     }
7128:     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7129:   }
7130:   /* Cleanup points */
7131:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7132:   /* Cleanup array */
7133:   PetscCall(VecRestoreArray(v, &array));
7134:   PetscFunctionReturn(PETSC_SUCCESS);
7135: }

7137: /* Check whether the given point is in the label. If not, update the offset to skip this point */
7138: static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7139: {
7140:   PetscFunctionBegin;
7141:   *contains = PETSC_TRUE;
7142:   if (label) {
7143:     PetscInt fdof;

7145:     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
7146:     if (!*contains) {
7147:       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7148:       *offset += fdof;
7149:       PetscFunctionReturn(PETSC_SUCCESS);
7150:     }
7151:   }
7152:   PetscFunctionReturn(PETSC_SUCCESS);
7153: }

7155: /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7156: 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)
7157: {
7158:   PetscSection    clSection;
7159:   IS              clPoints;
7160:   PetscScalar    *array;
7161:   PetscInt       *points = NULL;
7162:   const PetscInt *clp;
7163:   PetscInt        numFields, numPoints, p;
7164:   PetscInt        offset = 0, f;

7166:   PetscFunctionBeginHot;
7168:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7171:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7172:   /* Get points */
7173:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7174:   /* Get array */
7175:   PetscCall(VecGetArray(v, &array));
7176:   /* Get values */
7177:   for (f = 0; f < numFields; ++f) {
7178:     const PetscInt    **perms = NULL;
7179:     const PetscScalar **flips = NULL;
7180:     PetscBool           contains;

7182:     if (!fieldActive[f]) {
7183:       for (p = 0; p < numPoints * 2; p += 2) {
7184:         PetscInt fdof;
7185:         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7186:         offset += fdof;
7187:       }
7188:       continue;
7189:     }
7190:     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7191:     switch (mode) {
7192:     case INSERT_VALUES:
7193:       for (p = 0; p < numPoints; p++) {
7194:         const PetscInt     point = points[2 * p];
7195:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7196:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7197:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7198:         if (!contains) continue;
7199:         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
7200:       }
7201:       break;
7202:     case INSERT_ALL_VALUES:
7203:       for (p = 0; p < numPoints; p++) {
7204:         const PetscInt     point = points[2 * p];
7205:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7206:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7207:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7208:         if (!contains) continue;
7209:         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
7210:       }
7211:       break;
7212:     case INSERT_BC_VALUES:
7213:       for (p = 0; p < numPoints; p++) {
7214:         const PetscInt     point = points[2 * p];
7215:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7216:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7217:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7218:         if (!contains) continue;
7219:         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
7220:       }
7221:       break;
7222:     case ADD_VALUES:
7223:       for (p = 0; p < numPoints; p++) {
7224:         const PetscInt     point = points[2 * p];
7225:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7226:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7227:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7228:         if (!contains) continue;
7229:         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
7230:       }
7231:       break;
7232:     case ADD_ALL_VALUES:
7233:       for (p = 0; p < numPoints; p++) {
7234:         const PetscInt     point = points[2 * p];
7235:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7236:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7237:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7238:         if (!contains) continue;
7239:         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
7240:       }
7241:       break;
7242:     default:
7243:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7244:     }
7245:     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7246:   }
7247:   /* Cleanup points */
7248:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7249:   /* Cleanup array */
7250:   PetscCall(VecRestoreArray(v, &array));
7251:   PetscFunctionReturn(PETSC_SUCCESS);
7252: }

7254: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7255: {
7256:   PetscMPIInt rank;
7257:   PetscInt    i, j;

7259:   PetscFunctionBegin;
7260:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7261:   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
7262:   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
7263:   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7264:   numCIndices = numCIndices ? numCIndices : numRIndices;
7265:   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7266:   for (i = 0; i < numRIndices; i++) {
7267:     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7268:     for (j = 0; j < numCIndices; j++) {
7269: #if defined(PETSC_USE_COMPLEX)
7270:       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7271: #else
7272:       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7273: #endif
7274:     }
7275:     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7276:   }
7277:   PetscFunctionReturn(PETSC_SUCCESS);
7278: }

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

7283:   Input Parameters:
7284: + section - The section for this data layout
7285: . islocal - Is the section (and thus indices being requested) local or global?
7286: . point   - The point contributing dofs with these indices
7287: . off     - The global offset of this point
7288: . loff    - The local offset of each field
7289: . setBC   - The flag determining whether to include indices of boundary values
7290: . perm    - A permutation of the dofs on this point, or NULL
7291: - indperm - A permutation of the entire indices array, or NULL

7293:   Output Parameter:
7294: . indices - Indices for dofs on this point

7296:   Level: developer

7298:   Note: The indices could be local or global, depending on the value of 'off'.
7299: */
7300: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7301: {
7302:   PetscInt        dof;   /* The number of unknowns on this point */
7303:   PetscInt        cdof;  /* The number of constraints on this point */
7304:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7305:   PetscInt        cind = 0, k;

7307:   PetscFunctionBegin;
7308:   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7309:   PetscCall(PetscSectionGetDof(section, point, &dof));
7310:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7311:   if (!cdof || setBC) {
7312:     for (k = 0; k < dof; ++k) {
7313:       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7314:       const PetscInt ind    = indperm ? indperm[preind] : preind;

7316:       indices[ind] = off + k;
7317:     }
7318:   } else {
7319:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
7320:     for (k = 0; k < dof; ++k) {
7321:       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7322:       const PetscInt ind    = indperm ? indperm[preind] : preind;

7324:       if ((cind < cdof) && (k == cdofs[cind])) {
7325:         /* Insert check for returning constrained indices */
7326:         indices[ind] = -(off + k + 1);
7327:         ++cind;
7328:       } else {
7329:         indices[ind] = off + k - (islocal ? 0 : cind);
7330:       }
7331:     }
7332:   }
7333:   *loff += dof;
7334:   PetscFunctionReturn(PETSC_SUCCESS);
7335: }

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

7340:  Input Parameters:
7341: + section - a section (global or local)
7342: - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
7343: . point - point within section
7344: . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
7345: . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
7346: . setBC - identify constrained (boundary condition) points via involution.
7347: . perms - perms[f][permsoff][:] is a permutation of dofs within each field
7348: . permsoff - offset
7349: - indperm - index permutation

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

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

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

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

7368:  Example:
7369:  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
7370:  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
7371:  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
7372:  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.

7374:  Level: developer
7375: */
7376: 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[])
7377: {
7378:   PetscInt numFields, foff, f;

7380:   PetscFunctionBegin;
7381:   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7382:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7383:   for (f = 0, foff = 0; f < numFields; ++f) {
7384:     PetscInt        fdof, cfdof;
7385:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7386:     PetscInt        cind = 0, b;
7387:     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

7389:     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7390:     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7391:     if (!cfdof || setBC) {
7392:       for (b = 0; b < fdof; ++b) {
7393:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7394:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7396:         indices[ind] = off + foff + b;
7397:       }
7398:     } else {
7399:       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7400:       for (b = 0; b < fdof; ++b) {
7401:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7402:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7404:         if ((cind < cfdof) && (b == fcdofs[cind])) {
7405:           indices[ind] = -(off + foff + b + 1);
7406:           ++cind;
7407:         } else {
7408:           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7409:         }
7410:       }
7411:     }
7412:     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7413:     foffs[f] += fdof;
7414:   }
7415:   PetscFunctionReturn(PETSC_SUCCESS);
7416: }

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

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

7423:  Notes:
7424:  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7425:  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
7426: */
7427: static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7428: {
7429:   PetscInt numFields, foff, f;

7431:   PetscFunctionBegin;
7432:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7433:   for (f = 0; f < numFields; ++f) {
7434:     PetscInt        fdof, cfdof;
7435:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7436:     PetscInt        cind = 0, b;
7437:     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

7439:     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7440:     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7441:     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7442:     if (!cfdof) {
7443:       for (b = 0; b < fdof; ++b) {
7444:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7445:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7447:         indices[ind] = foff + b;
7448:       }
7449:     } else {
7450:       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7451:       for (b = 0; b < fdof; ++b) {
7452:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7453:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7455:         if ((cind < cfdof) && (b == fcdofs[cind])) {
7456:           indices[ind] = -(foff + b + 1);
7457:           ++cind;
7458:         } else {
7459:           indices[ind] = foff + b - cind;
7460:         }
7461:       }
7462:     }
7463:     foffs[f] += fdof;
7464:   }
7465:   PetscFunctionReturn(PETSC_SUCCESS);
7466: }

7468: static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms)
7469: {
7470:   PetscInt numFields, sStart, sEnd, cStart, cEnd;

7472:   PetscFunctionBegin;
7473:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7474:   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7475:   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7476:   for (PetscInt p = 0; p < nPoints; p++) {
7477:     PetscInt     b       = pnts[2 * p];
7478:     PetscInt     bSecDof = 0, bOff;
7479:     PetscInt     cSecDof = 0;
7480:     PetscSection indices_section;

7482:     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7483:     if (!bSecDof) continue;
7484:     if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof));
7485:     indices_section = cSecDof > 0 ? cSec : section;
7486:     if (numFields) {
7487:       PetscInt fStart[32], fEnd[32];

7489:       fStart[0] = 0;
7490:       fEnd[0]   = 0;
7491:       for (PetscInt f = 0; f < numFields; f++) {
7492:         PetscInt fDof = 0;

7494:         PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof));
7495:         fStart[f + 1] = fStart[f] + fDof;
7496:         fEnd[f + 1]   = fStart[f + 1];
7497:       }
7498:       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7499:       // only apply permutations on one side
7500:       PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices));
7501:       for (PetscInt f = 0; f < numFields; f++) {
7502:         for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); }
7503:       }
7504:     } else {
7505:       PetscInt bEnd = 0;

7507:       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7508:       PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices));

7510:       for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7511:     }
7512:   }
7513:   PetscFunctionReturn(PETSC_SUCCESS);
7514: }

7516: PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[])
7517: {
7518:   Mat             cMat;
7519:   PetscSection    aSec, cSec;
7520:   IS              aIS;
7521:   PetscInt        aStart = -1, aEnd = -1;
7522:   PetscInt        sStart = -1, sEnd = -1;
7523:   PetscInt        cStart = -1, cEnd = -1;
7524:   const PetscInt *anchors;
7525:   PetscInt        numFields, p;
7526:   PetscInt        newNumPoints = 0, newNumIndices = 0;
7527:   PetscInt       *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices;
7528:   PetscInt        oldOffsets[32];
7529:   PetscInt        newOffsets[32];
7530:   PetscInt        oldOffsetsCopy[32];
7531:   PetscInt        newOffsetsCopy[32];
7532:   PetscScalar    *modMat         = NULL;
7533:   PetscBool       anyConstrained = PETSC_FALSE;

7535:   PetscFunctionBegin;
7538:   PetscCall(PetscSectionGetNumFields(section, &numFields));

7540:   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7541:   /* if there are point-to-point constraints */
7542:   if (aSec) {
7543:     PetscCall(PetscArrayzero(newOffsets, 32));
7544:     PetscCall(PetscArrayzero(oldOffsets, 32));
7545:     PetscCall(ISGetIndices(aIS, &anchors));
7546:     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7547:     PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7548:     /* figure out how many points are going to be in the new element matrix
7549:      * (we allow double counting, because it's all just going to be summed
7550:      * into the global matrix anyway) */
7551:     for (p = 0; p < 2 * numPoints; p += 2) {
7552:       PetscInt b    = points[p];
7553:       PetscInt bDof = 0, bSecDof = 0;

7555:       if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7556:       if (!bSecDof) continue;

7558:       for (PetscInt f = 0; f < numFields; f++) {
7559:         PetscInt fDof = 0;

7561:         PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7562:         oldOffsets[f + 1] += fDof;
7563:       }
7564:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7565:       if (bDof) {
7566:         /* this point is constrained */
7567:         /* it is going to be replaced by its anchors */
7568:         PetscInt bOff, q;

7570:         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7571:         for (q = 0; q < bDof; q++) {
7572:           PetscInt a    = anchors[bOff + q];
7573:           PetscInt aDof = 0;

7575:           if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7576:           if (aDof) {
7577:             anyConstrained = PETSC_TRUE;
7578:             newNumPoints += 1;
7579:           }
7580:           newNumIndices += aDof;
7581:           for (PetscInt f = 0; f < numFields; ++f) {
7582:             PetscInt fDof = 0;

7584:             if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7585:             newOffsets[f + 1] += fDof;
7586:           }
7587:         }
7588:       } else {
7589:         /* this point is not constrained */
7590:         newNumPoints++;
7591:         newNumIndices += bSecDof;
7592:         for (PetscInt f = 0; f < numFields; ++f) {
7593:           PetscInt fDof;

7595:           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7596:           newOffsets[f + 1] += fDof;
7597:         }
7598:       }
7599:     }
7600:   }
7601:   if (!anyConstrained) {
7602:     if (outNumPoints) *outNumPoints = 0;
7603:     if (outNumIndices) *outNumIndices = 0;
7604:     if (outPoints) *outPoints = NULL;
7605:     if (outMat) *outMat = NULL;
7606:     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7607:     PetscFunctionReturn(PETSC_SUCCESS);
7608:   }

7610:   if (outNumPoints) *outNumPoints = newNumPoints;
7611:   if (outNumIndices) *outNumIndices = newNumIndices;

7613:   for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7614:   for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f];

7616:   if (!outPoints && !outMat) {
7617:     if (offsets) {
7618:       for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7619:     }
7620:     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7621:     PetscFunctionReturn(PETSC_SUCCESS);
7622:   }

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

7627:   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7628:   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));

7630:   /* output arrays */
7631:   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7632:   PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints));

7634:   // get the new Points
7635:   for (PetscInt p = 0, newP = 0; p < numPoints; p++) {
7636:     PetscInt b    = points[2 * p];
7637:     PetscInt bDof = 0, bSecDof = 0, bOff;

7639:     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7640:     if (!bSecDof) continue;
7641:     if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7642:     if (bDof) {
7643:       PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7644:       for (PetscInt q = 0; q < bDof; q++) {
7645:         PetscInt a = anchors[bOff + q], aDof = 0;

7647:         if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7648:         if (aDof) {
7649:           newPoints[2 * newP]     = a;
7650:           newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation
7651:           newP++;
7652:         }
7653:       }
7654:     } else {
7655:       newPoints[2 * newP]     = b;
7656:       newPoints[2 * newP + 1] = points[2 * p + 1];
7657:       newP++;
7658:     }
7659:   }

7661:   if (outMat) {
7662:     PetscScalar *tmpMat;
7663:     PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32));
7664:     PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32));

7666:     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices));
7667:     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7668:     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7669:     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));

7671:     for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1;
7672:     for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1;

7674:     PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms));
7675:     PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL));

7677:     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
7678:     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
7679:     PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices));
7680:     // for each field, insert the anchor modification into modMat
7681:     for (PetscInt f = 0; f < PetscMax(1, numFields); f++) {
7682:       PetscInt fStart    = oldOffsets[f];
7683:       PetscInt fNewStart = newOffsets[f];
7684:       for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) {
7685:         PetscInt b    = points[2 * p];
7686:         PetscInt bDof = 0, bSecDof = 0, bOff;

7688:         if (b >= sStart && b < sEnd) {
7689:           if (numFields) {
7690:             PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof));
7691:           } else {
7692:             PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7693:           }
7694:         }
7695:         if (!bSecDof) continue;
7696:         if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7697:         if (bDof) {
7698:           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7699:           for (PetscInt q = 0; q < bDof; q++, newP++) {
7700:             PetscInt a = anchors[bOff + q], aDof = 0;

7702:             if (a >= sStart && a < sEnd) {
7703:               if (numFields) {
7704:                 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
7705:               } else {
7706:                 PetscCall(PetscSectionGetDof(section, a, &aDof));
7707:               }
7708:             }
7709:             if (aDof) {
7710:               PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat));
7711:               for (PetscInt d = 0; d < bSecDof; d++) {
7712:                 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e];
7713:               }
7714:             }
7715:             oNew += aDof;
7716:           }
7717:         } else {
7718:           // Insert the identity matrix in this block
7719:           for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1;
7720:           oNew += bSecDof;
7721:           newP++;
7722:         }
7723:         o += bSecDof;
7724:       }
7725:     }

7727:     *outMat = modMat;

7729:     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
7730:     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7731:     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7732:     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7733:     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices));
7734:   }
7735:   PetscCall(ISRestoreIndices(aIS, &anchors));

7737:   /* output */
7738:   if (outPoints) {
7739:     *outPoints = newPoints;
7740:   } else {
7741:     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7742:   }
7743:   for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7744:   PetscFunctionReturn(PETSC_SUCCESS);
7745: }

7747: PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft)
7748: {
7749:   PetscScalar *modMat        = NULL;
7750:   PetscInt     newNumIndices = -1;

7752:   PetscFunctionBegin;
7753:   /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix.
7754:      modMat is that matrix C */
7755:   PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL));
7756:   if (outNumIndices) *outNumIndices = newNumIndices;
7757:   if (modMat) {
7758:     const PetscScalar *newValues = values;

7760:     if (multiplyRight) {
7761:       PetscScalar *newNewValues = NULL;
7762:       PetscBLASInt M            = newNumIndices;
7763:       PetscBLASInt N            = numRows;
7764:       PetscBLASInt K            = numIndices;
7765:       PetscScalar  a = 1.0, b = 0.0;

7767:       PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices);

7769:       PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues));
7770:       // row-major to column-major conversion, right multiplication becomes left multiplication
7771:       PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M));

7773:       numCols   = newNumIndices;
7774:       newValues = newNewValues;
7775:     }

7777:     if (multiplyLeft) {
7778:       PetscScalar *newNewValues = NULL;
7779:       PetscBLASInt M            = numCols;
7780:       PetscBLASInt N            = newNumIndices;
7781:       PetscBLASInt K            = numIndices;
7782:       PetscScalar  a = 1.0, b = 0.0;

7784:       PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices);

7786:       PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues));
7787:       // row-major to column-major conversion, left multiplication becomes right multiplication
7788:       PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M));
7789:       if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues));
7790:       newValues = newNewValues;
7791:     }
7792:     *outValues = (PetscScalar *)newValues;
7793:     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
7794:   }
7795:   PetscFunctionReturn(PETSC_SUCCESS);
7796: }

7798: PETSC_INTERN 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)
7799: {
7800:   PetscFunctionBegin;
7801:   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft));
7802:   PetscFunctionReturn(PETSC_SUCCESS);
7803: }

7805: static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize)
7806: {
7807:   /* Closure ordering */
7808:   PetscSection    clSection;
7809:   IS              clPoints;
7810:   const PetscInt *clp;
7811:   PetscInt       *points;
7812:   PetscInt        Ncl, Ni = 0;

7814:   PetscFunctionBeginHot;
7815:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7816:   for (PetscInt p = 0; p < Ncl * 2; p += 2) {
7817:     PetscInt dof;

7819:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
7820:     Ni += dof;
7821:   }
7822:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7823:   *closureSize = Ni;
7824:   PetscFunctionReturn(PETSC_SUCCESS);
7825: }

7827: static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft)
7828: {
7829:   /* Closure ordering */
7830:   PetscSection    clSection;
7831:   IS              clPoints;
7832:   const PetscInt *clp;
7833:   PetscInt       *points;
7834:   const PetscInt *clperm = NULL;
7835:   /* Dof permutation and sign flips */
7836:   const PetscInt    **perms[32] = {NULL};
7837:   const PetscScalar **flips[32] = {NULL};
7838:   PetscScalar        *valCopy   = NULL;
7839:   /* Hanging node constraints */
7840:   PetscInt    *pointsC = NULL;
7841:   PetscScalar *valuesC = NULL;
7842:   PetscInt     NclC, NiC;

7844:   PetscInt *idx;
7845:   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
7846:   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7847:   PetscInt  idxStart, idxEnd;
7848:   PetscInt  nRows, nCols;

7850:   PetscFunctionBeginHot;
7854:   PetscAssertPointer(numRows, 6);
7855:   PetscAssertPointer(numCols, 7);
7856:   if (indices) PetscAssertPointer(indices, 8);
7857:   if (outOffsets) PetscAssertPointer(outOffsets, 9);
7858:   if (values) PetscAssertPointer(values, 10);
7859:   PetscCall(PetscSectionGetNumFields(section, &Nf));
7860:   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
7861:   PetscCall(PetscArrayzero(offsets, 32));
7862:   /* 1) Get points in closure */
7863:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7864:   if (useClPerm) {
7865:     PetscInt depth, clsize;
7866:     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7867:     for (clsize = 0, p = 0; p < Ncl; p++) {
7868:       PetscInt dof;
7869:       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7870:       clsize += dof;
7871:     }
7872:     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7873:   }
7874:   /* 2) Get number of indices on these points and field offsets from section */
7875:   for (p = 0; p < Ncl * 2; p += 2) {
7876:     PetscInt dof, fdof;

7878:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
7879:     for (f = 0; f < Nf; ++f) {
7880:       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7881:       offsets[f + 1] += fdof;
7882:     }
7883:     Ni += dof;
7884:   }
7885:   if (*numRows == -1) *numRows = Ni;
7886:   if (*numCols == -1) *numCols = Ni;
7887:   nRows = *numRows;
7888:   nCols = *numCols;
7889:   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
7890:   PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni);
7891:   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7892:   if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols);
7893:   if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows);
7894:   for (f = 0; f < PetscMax(1, Nf); ++f) {
7895:     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7896:     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
7897:     /* may need to apply sign changes to the element matrix */
7898:     if (values && flips[f]) {
7899:       PetscInt foffset = offsets[f];

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

7905:         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
7906:         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
7907:         if (flip) {
7908:           PetscInt i, j, k;

7910:           if (!valCopy) {
7911:             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
7912:             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7913:             *values = valCopy;
7914:           }
7915:           for (i = 0; i < fdof; ++i) {
7916:             PetscScalar fval = flip[i];

7918:             if (multiplyRight) {
7919:               for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; }
7920:             }
7921:             if (multiplyLeft) {
7922:               for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; }
7923:             }
7924:           }
7925:         }
7926:         foffset += fdof;
7927:       }
7928:     }
7929:   }
7930:   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7931:   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft));
7932:   if (NclC) {
7933:     if (multiplyRight) { *numCols = nCols = NiC; }
7934:     if (multiplyLeft) { *numRows = nRows = NiC; }
7935:     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
7936:     for (f = 0; f < PetscMax(1, Nf); ++f) {
7937:       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7938:       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));