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, fStart = 0, fEnd = 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:     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
1115:     if (lflg) {
1116:       DMLabel lbl;

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

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

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

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

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

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

1177:     /* Plot vertices */
1178:     PetscCall(VecGetArray(coordinates, &coords));
1179:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1180:     for (v = vStart; v < vEnd; ++v) {
1181:       PetscInt  off, dof, d;
1182:       PetscBool isLabeled = PETSC_FALSE;

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

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

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

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

1297:           PetscCall(DMPlexGetCone(dm, c, &cone));
1298:           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1299:           for (e = 0; e < coneSize; ++e) {
1300:             const PetscInt *econe;

1302:             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
1303:             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));
1304:           }
1305:         } else {
1306:           PetscInt *closure = NULL;
1307:           PetscInt  closureSize, Nv = 0, v;

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

1313:             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1314:           }
1315:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1316:           for (v = 0; v <= Nv; ++v) {
1317:             const PetscInt vertex = closure[v % Nv];

1319:             if (v > 0) {
1320:               if (plotEdges) {
1321:                 const PetscInt *edge;
1322:                 PetscInt        endpoints[2], ne;

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

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

1391:       color = colors[depth % numColors];
1392:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
1393:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
1394:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1395:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++));
1396:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1398:       if (depth > 2) {
1399:         color = colors[1 % numColors];
1400:         PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n"));
1401:         PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n"));
1402:         PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1403:         PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++));
1404:         PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1405:       }

1407:       color = colors[1 % numColors];
1408:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
1409:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
1410:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1411:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++));
1412:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1414:       color = colors[0 % numColors];
1415:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
1416:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
1417:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1418:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++));
1419:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1421:       for (p = pStart; p < pEnd; ++p) {
1422:         const PetscInt *cone;
1423:         PetscInt        coneSize, cp;

1425:         PetscCall(DMPlexGetCone(dm, p, &cone));
1426:         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1427:         for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1428:       }
1429:     }
1430:     PetscCall(PetscViewerFlush(viewer));
1431:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1432:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
1433:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
1434:     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
1435:     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
1436:     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
1437:     PetscCall(PetscFree3(names, colors, lcolors));
1438:     PetscCall(PetscBTDestroy(&wp));
1439:   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1440:     Vec                    cown, acown;
1441:     VecScatter             sct;
1442:     ISLocalToGlobalMapping g2l;
1443:     IS                     gid, acis;
1444:     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
1445:     MPI_Group              ggroup, ngroup;
1446:     PetscScalar           *array, nid;
1447:     const PetscInt        *idxs;
1448:     PetscInt              *idxs2, *start, *adjacency, *work;
1449:     PetscInt64             lm[3], gm[3];
1450:     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
1451:     PetscMPIInt            d1, d2, rank;

1453:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1454:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1455: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1456:     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
1457: #endif
1458:     if (ncomm != MPI_COMM_NULL) {
1459:       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
1460:       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
1461:       d1 = 0;
1462:       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
1463:       nid = d2;
1464:       PetscCallMPI(MPI_Group_free(&ggroup));
1465:       PetscCallMPI(MPI_Group_free(&ngroup));
1466:       PetscCallMPI(MPI_Comm_free(&ncomm));
1467:     } else nid = 0.0;

1469:     /* Get connectivity */
1470:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1471:     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));

1473:     /* filter overlapped local cells */
1474:     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
1475:     PetscCall(ISGetIndices(gid, &idxs));
1476:     PetscCall(ISGetLocalSize(gid, &cum));
1477:     PetscCall(PetscMalloc1(cum, &idxs2));
1478:     for (c = cStart, cum = 0; c < cEnd; c++) {
1479:       if (idxs[c - cStart] < 0) continue;
1480:       idxs2[cum++] = idxs[c - cStart];
1481:     }
1482:     PetscCall(ISRestoreIndices(gid, &idxs));
1483:     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
1484:     PetscCall(ISDestroy(&gid));
1485:     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));

1487:     /* support for node-aware cell locality */
1488:     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
1489:     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
1490:     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
1491:     PetscCall(VecGetArray(cown, &array));
1492:     for (c = 0; c < numVertices; c++) array[c] = nid;
1493:     PetscCall(VecRestoreArray(cown, &array));
1494:     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
1495:     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1496:     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1497:     PetscCall(ISDestroy(&acis));
1498:     PetscCall(VecScatterDestroy(&sct));
1499:     PetscCall(VecDestroy(&cown));

1501:     /* compute edgeCut */
1502:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
1503:     PetscCall(PetscMalloc1(cum, &work));
1504:     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
1505:     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
1506:     PetscCall(ISDestroy(&gid));
1507:     PetscCall(VecGetArray(acown, &array));
1508:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1509:       PetscInt totl;

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

1550:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1551:     PetscCallMPI(MPI_Comm_size(comm, &size));
1552:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1553:     PetscCall(DMGetDimension(dm, &dim));
1554:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1555:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1556:     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1557:     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
1558:     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
1559:     PetscCall(DMPlexGetDepth(dm, &locDepth));
1560:     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
1561:     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1562:     gcNum = gcEnd - gcStart;
1563:     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
1564:     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1565:     for (d = 0; d <= depth; d++) {
1566:       PetscInt Nc[2] = {0, 0}, ict;

1568:       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1569:       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1570:       ict = ct0;
1571:       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1572:       ct0 = (DMPolytopeType)ict;
1573:       for (p = pStart; p < pEnd; ++p) {
1574:         DMPolytopeType ct;

1576:         PetscCall(DMPlexGetCellType(dm, p, &ct));
1577:         if (ct == ct0) ++Nc[0];
1578:         else ++Nc[1];
1579:       }
1580:       if (size < maxSize) {
1581:         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
1582:         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
1583:         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
1584:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1585:         for (p = 0; p < size; ++p) {
1586:           if (rank == 0) {
1587:             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
1588:             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
1589:             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1590:           }
1591:         }
1592:       } else {
1593:         PetscInt locMinMax[2];

1595:         locMinMax[0] = Nc[0] + Nc[1];
1596:         locMinMax[1] = Nc[0] + Nc[1];
1597:         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1598:         locMinMax[0] = Nc[1];
1599:         locMinMax[1] = Nc[1];
1600:         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1601:         if (d == depth) {
1602:           locMinMax[0] = gcNum;
1603:           locMinMax[1] = gcNum;
1604:           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1605:         }
1606:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1607:         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
1608:         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
1609:         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1610:       }
1611:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1612:     }
1613:     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
1614:     {
1615:       const PetscReal *maxCell;
1616:       const PetscReal *L;
1617:       PetscBool        localized;

1619:       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
1620:       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1621:       if (L || localized) {
1622:         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
1623:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1624:         if (L) {
1625:           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
1626:           for (d = 0; d < dim; ++d) {
1627:             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1628:             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
1629:           }
1630:           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
1631:         }
1632:         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
1633:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1634:       }
1635:     }
1636:     PetscCall(DMGetNumLabels(dm, &numLabels));
1637:     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1638:     for (l = 0; l < numLabels; ++l) {
1639:       DMLabel         label;
1640:       const char     *name;
1641:       IS              valueIS;
1642:       const PetscInt *values;
1643:       PetscInt        numValues, v;

1645:       PetscCall(DMGetLabelName(dm, l, &name));
1646:       PetscCall(DMGetLabel(dm, name, &label));
1647:       PetscCall(DMLabelGetNumValues(label, &numValues));
1648:       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1649:       PetscCall(DMLabelGetValueIS(label, &valueIS));
1650:       PetscCall(ISGetIndices(valueIS, &values));
1651:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1652:       for (v = 0; v < numValues; ++v) {
1653:         PetscInt size;

1655:         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
1656:         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1657:         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1658:       }
1659:       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
1660:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1661:       PetscCall(ISRestoreIndices(valueIS, &values));
1662:       PetscCall(ISDestroy(&valueIS));
1663:     }
1664:     {
1665:       char    **labelNames;
1666:       PetscInt  Nl = numLabels;
1667:       PetscBool flg;

1669:       PetscCall(PetscMalloc1(Nl, &labelNames));
1670:       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1671:       for (l = 0; l < Nl; ++l) {
1672:         DMLabel label;

1674:         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1675:         if (flg) {
1676:           PetscCall(DMGetLabel(dm, labelNames[l], &label));
1677:           PetscCall(DMLabelView(label, viewer));
1678:         }
1679:         PetscCall(PetscFree(labelNames[l]));
1680:       }
1681:       PetscCall(PetscFree(labelNames));
1682:     }
1683:     /* If no fields are specified, people do not want to see adjacency */
1684:     if (dm->Nf) {
1685:       PetscInt f;

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

1690:         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
1691:         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
1692:         PetscCall(PetscViewerASCIIPushTab(viewer));
1693:         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
1694:         if (dm->fields[f].adjacency[0]) {
1695:           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
1696:           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
1697:         } else {
1698:           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
1699:           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
1700:         }
1701:         PetscCall(PetscViewerASCIIPopTab(viewer));
1702:       }
1703:     }
1704:     PetscCall(DMGetCoarseDM(dm, &cdm));
1705:     if (cdm) {
1706:       PetscCall(PetscViewerASCIIPushTab(viewer));
1707:       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
1708:       PetscCall(DMPlexView_Ascii(cdm, viewer));
1709:       PetscCall(PetscViewerASCIIPopTab(viewer));
1710:     }
1711:   }
1712:   PetscFunctionReturn(PETSC_SUCCESS);
1713: }

1715: static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1716: {
1717:   DMPolytopeType ct;
1718:   PetscMPIInt    rank;
1719:   PetscInt       cdim;

1721:   PetscFunctionBegin;
1722:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1723:   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1724:   PetscCall(DMGetCoordinateDim(dm, &cdim));
1725:   switch (ct) {
1726:   case DM_POLYTOPE_SEGMENT:
1727:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1728:     switch (cdim) {
1729:     case 1: {
1730:       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1731:       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */

1733:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
1734:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
1735:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
1736:     } break;
1737:     case 2: {
1738:       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1739:       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1740:       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);

1742:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1743:       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));
1744:       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));
1745:     } break;
1746:     default:
1747:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1748:     }
1749:     break;
1750:   case DM_POLYTOPE_TRIANGLE:
1751:     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));
1752:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1753:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), 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_QUADRILATERAL:
1757:     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));
1758:     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));
1759:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1760:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1761:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1762:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1763:     break;
1764:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1765:     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));
1766:     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));
1767:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1768:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1769:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1770:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1771:     break;
1772:   case DM_POLYTOPE_FV_GHOST:
1773:     break;
1774:   default:
1775:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1776:   }
1777:   PetscFunctionReturn(PETSC_SUCCESS);
1778: }

1780: static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1781: {
1782:   PetscReal   centroid[2] = {0., 0.};
1783:   PetscMPIInt rank;
1784:   PetscInt    fillColor;

1786:   PetscFunctionBegin;
1787:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1788:   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1789:   for (PetscInt v = 0; v < Nv; ++v) {
1790:     centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv;
1791:     centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv;
1792:   }
1793:   for (PetscInt e = 0; e < Nv; ++e) {
1794:     refCoords[0] = refVertices[e * 2 + 0];
1795:     refCoords[1] = refVertices[e * 2 + 1];
1796:     for (PetscInt d = 1; d <= edgeDiv; ++d) {
1797:       refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv;
1798:       refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv;
1799:     }
1800:     PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1801:     for (PetscInt d = 0; d < edgeDiv; ++d) {
1802:       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));
1803:       PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK));
1804:     }
1805:   }
1806:   PetscFunctionReturn(PETSC_SUCCESS);
1807: }

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

1813:   PetscFunctionBegin;
1814:   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1815:   switch (ct) {
1816:   case DM_POLYTOPE_TRIANGLE: {
1817:     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};

1819:     PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1820:   } break;
1821:   case DM_POLYTOPE_QUADRILATERAL: {
1822:     PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.};

1824:     PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1825:   } break;
1826:   default:
1827:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1828:   }
1829:   PetscFunctionReturn(PETSC_SUCCESS);
1830: }

1832: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1833: {
1834:   PetscDraw    draw;
1835:   DM           cdm;
1836:   PetscSection coordSection;
1837:   Vec          coordinates;
1838:   PetscReal    xyl[3], xyr[3];
1839:   PetscReal   *refCoords, *edgeCoords;
1840:   PetscBool    isnull, drawAffine;
1841:   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv;

1843:   PetscFunctionBegin;
1844:   PetscCall(DMGetCoordinateDim(dm, &dim));
1845:   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1846:   PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree));
1847:   drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE;
1848:   edgeDiv    = cDegree + 1;
1849:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
1850:   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
1851:   PetscCall(DMGetCoordinateDM(dm, &cdm));
1852:   PetscCall(DMGetLocalSection(cdm, &coordSection));
1853:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1854:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1855:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));

1857:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1858:   PetscCall(PetscDrawIsNull(draw, &isnull));
1859:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
1860:   PetscCall(PetscDrawSetTitle(draw, "Mesh"));

1862:   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
1863:   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
1864:   PetscCall(PetscDrawClear(draw));

1866:   for (c = cStart; c < cEnd; ++c) {
1867:     PetscScalar       *coords = NULL;
1868:     const PetscScalar *coords_arr;
1869:     PetscInt           numCoords;
1870:     PetscBool          isDG;

1872:     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1873:     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
1874:     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1875:     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1876:   }
1877:   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
1878:   PetscCall(PetscDrawFlush(draw));
1879:   PetscCall(PetscDrawPause(draw));
1880:   PetscCall(PetscDrawSave(draw));
1881:   PetscFunctionReturn(PETSC_SUCCESS);
1882: }

1884: static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1885: {
1886:   DM           odm = dm, rdm = dm, cdm;
1887:   PetscFE      fe;
1888:   PetscSpace   sp;
1889:   PetscClassId id;
1890:   PetscInt     degree;
1891:   PetscBool    hoView = PETSC_TRUE;

1893:   PetscFunctionBegin;
1894:   PetscObjectOptionsBegin((PetscObject)dm);
1895:   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
1896:   PetscOptionsEnd();
1897:   PetscCall(PetscObjectReference((PetscObject)dm));
1898:   *hdm = dm;
1899:   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
1900:   PetscCall(DMGetCoordinateDM(dm, &cdm));
1901:   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
1902:   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
1903:   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
1904:   PetscCall(PetscFEGetBasisSpace(fe, &sp));
1905:   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
1906:   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
1907:     DM  cdm, rcdm;
1908:     Mat In;
1909:     Vec cl, rcl;

1911:     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
1912:     PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL));
1913:     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
1914:     PetscCall(DMGetCoordinateDM(odm, &cdm));
1915:     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
1916:     PetscCall(DMGetCoordinatesLocal(odm, &cl));
1917:     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
1918:     PetscCall(DMSetCoarseDM(rcdm, cdm));
1919:     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
1920:     PetscCall(MatMult(In, cl, rcl));
1921:     PetscCall(MatDestroy(&In));
1922:     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
1923:     PetscCall(DMDestroy(&odm));
1924:     odm = rdm;
1925:   }
1926:   *hdm = rdm;
1927:   PetscFunctionReturn(PETSC_SUCCESS);
1928: }

1930: #if defined(PETSC_HAVE_EXODUSII)
1931:   #include <exodusII.h>
1932: #include <petscviewerexodusii.h>
1933: #endif

1935: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1936: {
1937:   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1938:   char      name[PETSC_MAX_PATH_LEN];

1940:   PetscFunctionBegin;
1943:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1944:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
1945:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1946:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1947:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
1948:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
1949:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1950:   if (iascii) {
1951:     PetscViewerFormat format;
1952:     PetscCall(PetscViewerGetFormat(viewer, &format));
1953:     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
1954:     else PetscCall(DMPlexView_Ascii(dm, viewer));
1955:   } else if (ishdf5) {
1956: #if defined(PETSC_HAVE_HDF5)
1957:     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1958: #else
1959:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1960: #endif
1961:   } else if (isvtk) {
1962:     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1963:   } else if (isdraw) {
1964:     DM hdm;

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

2009:     PetscCall(DMGetLabel(dm, name, &label));
2010:     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
2011:     PetscCall(DMPlexCreateLabelField(dm, label, &val));
2012:     PetscCall(VecView(val, viewer));
2013:     PetscCall(VecDestroy(&val));
2014:   }
2015:   PetscFunctionReturn(PETSC_SUCCESS);
2016: }

2018: /*@
2019:   DMPlexTopologyView - Saves a `DMPLEX` topology into a file

2021:   Collective

2023:   Input Parameters:
2024: + dm     - The `DM` whose topology is to be saved
2025: - viewer - The `PetscViewer` to save it in

2027:   Level: advanced

2029: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
2030: @*/
2031: PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2032: {
2033:   PetscBool ishdf5;

2035:   PetscFunctionBegin;
2038:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2039:   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
2040:   if (ishdf5) {
2041: #if defined(PETSC_HAVE_HDF5)
2042:     PetscViewerFormat format;
2043:     PetscCall(PetscViewerGetFormat(viewer, &format));
2044:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2045:       IS globalPointNumbering;

2047:       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
2048:       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
2049:       PetscCall(ISDestroy(&globalPointNumbering));
2050:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
2051: #else
2052:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2053: #endif
2054:   }
2055:   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
2056:   PetscFunctionReturn(PETSC_SUCCESS);
2057: }

2059: /*@
2060:   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file

2062:   Collective

2064:   Input Parameters:
2065: + dm     - The `DM` whose coordinates are to be saved
2066: - viewer - The `PetscViewer` for saving

2068:   Level: advanced

2070: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
2071: @*/
2072: PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2073: {
2074:   PetscBool ishdf5;

2076:   PetscFunctionBegin;
2079:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2080:   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
2081:   if (ishdf5) {
2082: #if defined(PETSC_HAVE_HDF5)
2083:     PetscViewerFormat format;
2084:     PetscCall(PetscViewerGetFormat(viewer, &format));
2085:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2086:       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
2087:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
2088: #else
2089:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2090: #endif
2091:   }
2092:   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
2093:   PetscFunctionReturn(PETSC_SUCCESS);
2094: }

2096: /*@
2097:   DMPlexLabelsView - Saves `DMPLEX` labels into a file

2099:   Collective

2101:   Input Parameters:
2102: + dm     - The `DM` whose labels are to be saved
2103: - viewer - The `PetscViewer` for saving

2105:   Level: advanced

2107: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2108: @*/
2109: PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2110: {
2111:   PetscBool ishdf5;

2113:   PetscFunctionBegin;
2116:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2117:   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2118:   if (ishdf5) {
2119: #if defined(PETSC_HAVE_HDF5)
2120:     IS                globalPointNumbering;
2121:     PetscViewerFormat format;

2123:     PetscCall(PetscViewerGetFormat(viewer, &format));
2124:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2125:       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
2126:       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
2127:       PetscCall(ISDestroy(&globalPointNumbering));
2128:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2129: #else
2130:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2131: #endif
2132:   }
2133:   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
2134:   PetscFunctionReturn(PETSC_SUCCESS);
2135: }

2137: /*@
2138:   DMPlexSectionView - Saves a section associated with a `DMPLEX`

2140:   Collective

2142:   Input Parameters:
2143: + dm        - The `DM` that contains the topology on which the section to be saved is defined
2144: . viewer    - The `PetscViewer` for saving
2145: - sectiondm - The `DM` that contains the section to be saved, can be `NULL`

2147:   Level: advanced

2149:   Notes:
2150:   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.

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

2154: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2155: @*/
2156: PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2157: {
2158:   PetscBool ishdf5;

2160:   PetscFunctionBegin;
2163:   if (!sectiondm) sectiondm = dm;
2165:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2166:   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2167:   if (ishdf5) {
2168: #if defined(PETSC_HAVE_HDF5)
2169:     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2170: #else
2171:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2172: #endif
2173:   }
2174:   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
2175:   PetscFunctionReturn(PETSC_SUCCESS);
2176: }

2178: /*@
2179:   DMPlexGlobalVectorView - Saves a global vector

2181:   Collective

2183:   Input Parameters:
2184: + dm        - The `DM` that represents the topology
2185: . viewer    - The `PetscViewer` to save data with
2186: . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2187: - vec       - The global vector to be saved

2189:   Level: advanced

2191:   Notes:
2192:   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.

2194:   Calling sequence:
2195: .vb
2196:        DMCreate(PETSC_COMM_WORLD, &dm);
2197:        DMSetType(dm, DMPLEX);
2198:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2199:        DMClone(dm, &sectiondm);
2200:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2201:        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2202:        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2203:        PetscSectionSetChart(section, pStart, pEnd);
2204:        PetscSectionSetUp(section);
2205:        DMSetLocalSection(sectiondm, section);
2206:        PetscSectionDestroy(&section);
2207:        DMGetGlobalVector(sectiondm, &vec);
2208:        PetscObjectSetName((PetscObject)vec, "vec_name");
2209:        DMPlexTopologyView(dm, viewer);
2210:        DMPlexSectionView(dm, viewer, sectiondm);
2211:        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2212:        DMRestoreGlobalVector(sectiondm, &vec);
2213:        DMDestroy(&sectiondm);
2214:        DMDestroy(&dm);
2215: .ve

2217: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2218: @*/
2219: PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2220: {
2221:   PetscBool ishdf5;

2223:   PetscFunctionBegin;
2226:   if (!sectiondm) sectiondm = dm;
2229:   /* Check consistency */
2230:   {
2231:     PetscSection section;
2232:     PetscBool    includesConstraints;
2233:     PetscInt     m, m1;

2235:     PetscCall(VecGetLocalSize(vec, &m1));
2236:     PetscCall(DMGetGlobalSection(sectiondm, &section));
2237:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2238:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2239:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2240:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2241:   }
2242:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2243:   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2244:   if (ishdf5) {
2245: #if defined(PETSC_HAVE_HDF5)
2246:     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2247: #else
2248:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2249: #endif
2250:   }
2251:   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2252:   PetscFunctionReturn(PETSC_SUCCESS);
2253: }

2255: /*@
2256:   DMPlexLocalVectorView - Saves a local vector

2258:   Collective

2260:   Input Parameters:
2261: + dm        - The `DM` that represents the topology
2262: . viewer    - The `PetscViewer` to save data with
2263: . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL`
2264: - vec       - The local vector to be saved

2266:   Level: advanced

2268:   Note:
2269:   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.

2271:   Calling sequence:
2272: .vb
2273:        DMCreate(PETSC_COMM_WORLD, &dm);
2274:        DMSetType(dm, DMPLEX);
2275:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2276:        DMClone(dm, &sectiondm);
2277:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2278:        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2279:        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2280:        PetscSectionSetChart(section, pStart, pEnd);
2281:        PetscSectionSetUp(section);
2282:        DMSetLocalSection(sectiondm, section);
2283:        DMGetLocalVector(sectiondm, &vec);
2284:        PetscObjectSetName((PetscObject)vec, "vec_name");
2285:        DMPlexTopologyView(dm, viewer);
2286:        DMPlexSectionView(dm, viewer, sectiondm);
2287:        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2288:        DMRestoreLocalVector(sectiondm, &vec);
2289:        DMDestroy(&sectiondm);
2290:        DMDestroy(&dm);
2291: .ve

2293: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2294: @*/
2295: PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2296: {
2297:   PetscBool ishdf5;

2299:   PetscFunctionBegin;
2302:   if (!sectiondm) sectiondm = dm;
2305:   /* Check consistency */
2306:   {
2307:     PetscSection section;
2308:     PetscBool    includesConstraints;
2309:     PetscInt     m, m1;

2311:     PetscCall(VecGetLocalSize(vec, &m1));
2312:     PetscCall(DMGetLocalSection(sectiondm, &section));
2313:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2314:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2315:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2316:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2317:   }
2318:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2319:   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2320:   if (ishdf5) {
2321: #if defined(PETSC_HAVE_HDF5)
2322:     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2323: #else
2324:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2325: #endif
2326:   }
2327:   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2328:   PetscFunctionReturn(PETSC_SUCCESS);
2329: }

2331: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2332: {
2333:   PetscBool ishdf5;

2335:   PetscFunctionBegin;
2338:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2339:   if (ishdf5) {
2340: #if defined(PETSC_HAVE_HDF5)
2341:     PetscViewerFormat format;
2342:     PetscCall(PetscViewerGetFormat(viewer, &format));
2343:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2344:       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2345:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2346:       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
2347:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2348:     PetscFunctionReturn(PETSC_SUCCESS);
2349: #else
2350:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2351: #endif
2352:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2353: }

2355: /*@
2356:   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`

2358:   Collective

2360:   Input Parameters:
2361: + dm     - The `DM` into which the topology is loaded
2362: - viewer - The `PetscViewer` for the saved topology

2364:   Output Parameter:
2365: . 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

2367:   Level: advanced

2369: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2370:           `PetscViewer`, `PetscSF`
2371: @*/
2372: PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2373: {
2374:   PetscBool ishdf5;

2376:   PetscFunctionBegin;
2379:   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
2380:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2381:   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2382:   if (ishdf5) {
2383: #if defined(PETSC_HAVE_HDF5)
2384:     PetscViewerFormat format;
2385:     PetscCall(PetscViewerGetFormat(viewer, &format));
2386:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2387:       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2388:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2389: #else
2390:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2391: #endif
2392:   }
2393:   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2394:   PetscFunctionReturn(PETSC_SUCCESS);
2395: }

2397: /*@
2398:   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`

2400:   Collective

2402:   Input Parameters:
2403: + dm                   - The `DM` into which the coordinates are loaded
2404: . viewer               - The `PetscViewer` for the saved coordinates
2405: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer

2407:   Level: advanced

2409: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2410:           `PetscSF`, `PetscViewer`
2411: @*/
2412: PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2413: {
2414:   PetscBool ishdf5;

2416:   PetscFunctionBegin;
2420:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2421:   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2422:   if (ishdf5) {
2423: #if defined(PETSC_HAVE_HDF5)
2424:     PetscViewerFormat format;
2425:     PetscCall(PetscViewerGetFormat(viewer, &format));
2426:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2427:       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2428:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2429: #else
2430:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2431: #endif
2432:   }
2433:   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2434:   PetscFunctionReturn(PETSC_SUCCESS);
2435: }

2437: /*@
2438:   DMPlexLabelsLoad - Loads labels into a `DMPLEX`

2440:   Collective

2442:   Input Parameters:
2443: + dm                   - The `DM` into which the labels are loaded
2444: . viewer               - The `PetscViewer` for the saved labels
2445: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer

2447:   Level: advanced

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

2452: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2453:           `PetscSF`, `PetscViewer`
2454: @*/
2455: PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2456: {
2457:   PetscBool ishdf5;

2459:   PetscFunctionBegin;
2463:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2464:   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2465:   if (ishdf5) {
2466: #if defined(PETSC_HAVE_HDF5)
2467:     PetscViewerFormat format;

2469:     PetscCall(PetscViewerGetFormat(viewer, &format));
2470:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2471:       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2472:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2473: #else
2474:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2475: #endif
2476:   }
2477:   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2478:   PetscFunctionReturn(PETSC_SUCCESS);
2479: }

2481: /*@
2482:   DMPlexSectionLoad - Loads section into a `DMPLEX`

2484:   Collective

2486:   Input Parameters:
2487: + dm                   - The `DM` that represents the topology
2488: . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
2489: . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL`
2490: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer

2492:   Output Parameters:
2493: + 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)
2494: - 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)

2496:   Level: advanced

2498:   Notes:
2499:   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.

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

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

2505:   Example using 2 processes:
2506: .vb
2507:   NX (number of points on dm): 4
2508:   sectionA                   : the on-disk section
2509:   vecA                       : a vector associated with sectionA
2510:   sectionB                   : sectiondm's local section constructed in this function
2511:   vecB (local)               : a vector associated with sectiondm's local section
2512:   vecB (global)              : a vector associated with sectiondm's global section

2514:                                      rank 0    rank 1
2515:   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2516:   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2517:   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2518:   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2519:   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2520:   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2521:   sectionB->atlasDof             :     1 0 1 | 1 3
2522:   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2523:   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2524:   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2525: .ve
2526:   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.

2528: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2529: @*/
2530: PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2531: {
2532:   PetscBool ishdf5;

2534:   PetscFunctionBegin;
2537:   if (!sectiondm) sectiondm = dm;
2540:   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
2541:   if (localDofSF) PetscAssertPointer(localDofSF, 6);
2542:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2543:   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2544:   if (ishdf5) {
2545: #if defined(PETSC_HAVE_HDF5)
2546:     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2547: #else
2548:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2549: #endif
2550:   }
2551:   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2552:   PetscFunctionReturn(PETSC_SUCCESS);
2553: }

2555: /*@
2556:   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector

2558:   Collective

2560:   Input Parameters:
2561: + dm        - The `DM` that represents the topology
2562: . viewer    - The `PetscViewer` that represents the on-disk vector data
2563: . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2564: . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2565: - vec       - The global vector to set values of

2567:   Level: advanced

2569:   Notes:
2570:   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.

2572:   Calling sequence:
2573: .vb
2574:        DMCreate(PETSC_COMM_WORLD, &dm);
2575:        DMSetType(dm, DMPLEX);
2576:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2577:        DMPlexTopologyLoad(dm, viewer, &sfX);
2578:        DMClone(dm, &sectiondm);
2579:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2580:        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2581:        DMGetGlobalVector(sectiondm, &vec);
2582:        PetscObjectSetName((PetscObject)vec, "vec_name");
2583:        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2584:        DMRestoreGlobalVector(sectiondm, &vec);
2585:        PetscSFDestroy(&gsf);
2586:        PetscSFDestroy(&sfX);
2587:        DMDestroy(&sectiondm);
2588:        DMDestroy(&dm);
2589: .ve

2591: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2592:           `PetscSF`, `PetscViewer`
2593: @*/
2594: PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2595: {
2596:   PetscBool ishdf5;

2598:   PetscFunctionBegin;
2601:   if (!sectiondm) sectiondm = dm;
2605:   /* Check consistency */
2606:   {
2607:     PetscSection section;
2608:     PetscBool    includesConstraints;
2609:     PetscInt     m, m1;

2611:     PetscCall(VecGetLocalSize(vec, &m1));
2612:     PetscCall(DMGetGlobalSection(sectiondm, &section));
2613:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2614:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2615:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2616:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2617:   }
2618:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2619:   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2620:   if (ishdf5) {
2621: #if defined(PETSC_HAVE_HDF5)
2622:     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2623: #else
2624:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2625: #endif
2626:   }
2627:   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2628:   PetscFunctionReturn(PETSC_SUCCESS);
2629: }

2631: /*@
2632:   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector

2634:   Collective

2636:   Input Parameters:
2637: + dm        - The `DM` that represents the topology
2638: . viewer    - The `PetscViewer` that represents the on-disk vector data
2639: . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL`
2640: . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2641: - vec       - The local vector to set values of

2643:   Level: advanced

2645:   Notes:
2646:   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.

2648:   Calling sequence:
2649: .vb
2650:        DMCreate(PETSC_COMM_WORLD, &dm);
2651:        DMSetType(dm, DMPLEX);
2652:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2653:        DMPlexTopologyLoad(dm, viewer, &sfX);
2654:        DMClone(dm, &sectiondm);
2655:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2656:        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2657:        DMGetLocalVector(sectiondm, &vec);
2658:        PetscObjectSetName((PetscObject)vec, "vec_name");
2659:        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2660:        DMRestoreLocalVector(sectiondm, &vec);
2661:        PetscSFDestroy(&lsf);
2662:        PetscSFDestroy(&sfX);
2663:        DMDestroy(&sectiondm);
2664:        DMDestroy(&dm);
2665: .ve

2667: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2668:           `PetscSF`, `PetscViewer`
2669: @*/
2670: PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2671: {
2672:   PetscBool ishdf5;

2674:   PetscFunctionBegin;
2677:   if (!sectiondm) sectiondm = dm;
2681:   /* Check consistency */
2682:   {
2683:     PetscSection section;
2684:     PetscBool    includesConstraints;
2685:     PetscInt     m, m1;

2687:     PetscCall(VecGetLocalSize(vec, &m1));
2688:     PetscCall(DMGetLocalSection(sectiondm, &section));
2689:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2690:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2691:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2692:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2693:   }
2694:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2695:   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2696:   if (ishdf5) {
2697: #if defined(PETSC_HAVE_HDF5)
2698:     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2699: #else
2700:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2701: #endif
2702:   }
2703:   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2704:   PetscFunctionReturn(PETSC_SUCCESS);
2705: }

2707: PetscErrorCode DMDestroy_Plex(DM dm)
2708: {
2709:   DM_Plex *mesh = (DM_Plex *)dm->data;

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

2776: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2777: {
2778:   PetscSection           sectionGlobal, sectionLocal;
2779:   PetscInt               bs = -1, mbs;
2780:   PetscInt               localSize, localStart = 0;
2781:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2782:   MatType                mtype;
2783:   ISLocalToGlobalMapping ltog;

2785:   PetscFunctionBegin;
2786:   PetscCall(MatInitializePackage());
2787:   mtype = dm->mattype;
2788:   PetscCall(DMGetLocalSection(dm, &sectionLocal));
2789:   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
2790:   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
2791:   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2792:   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
2793:   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
2794:   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
2795:   PetscCall(MatSetType(*J, mtype));
2796:   PetscCall(MatSetFromOptions(*J));
2797:   PetscCall(MatGetBlockSize(*J, &mbs));
2798:   if (mbs > 1) bs = mbs;
2799:   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
2800:   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
2801:   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
2802:   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
2803:   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
2804:   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
2805:   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
2806:   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2807:   if (!isShell) {
2808:     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2809:     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2810:     PetscInt  pStart, pEnd, p, dof, cdof, num_fields;

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

2814:     PetscCall(PetscCalloc1(localSize, &pblocks));
2815:     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2816:     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2817:     for (p = pStart; p < pEnd; ++p) {
2818:       switch (dm->blocking_type) {
2819:       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
2820:         PetscInt bdof, offset;

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

2902: /*@
2903:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

2905:   Not Collective

2907:   Input Parameter:
2908: . dm - The `DMPLEX`

2910:   Output Parameter:
2911: . subsection - The subdomain section

2913:   Level: developer

2915: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
2916: @*/
2917: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2918: {
2919:   DM_Plex *mesh = (DM_Plex *)dm->data;

2921:   PetscFunctionBegin;
2923:   if (!mesh->subdomainSection) {
2924:     PetscSection section;
2925:     PetscSF      sf;

2927:     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
2928:     PetscCall(DMGetLocalSection(dm, &section));
2929:     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
2930:     PetscCall(PetscSFDestroy(&sf));
2931:   }
2932:   *subsection = mesh->subdomainSection;
2933:   PetscFunctionReturn(PETSC_SUCCESS);
2934: }

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

2939:   Not Collective

2941:   Input Parameter:
2942: . dm - The `DMPLEX`

2944:   Output Parameters:
2945: + pStart - The first mesh point
2946: - pEnd   - The upper bound for mesh points

2948:   Level: beginner

2950: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2951: @*/
2952: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2953: {
2954:   DM_Plex *mesh = (DM_Plex *)dm->data;

2956:   PetscFunctionBegin;
2958:   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
2959:   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2960:   PetscFunctionReturn(PETSC_SUCCESS);
2961: }

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

2966:   Not Collective

2968:   Input Parameters:
2969: + dm     - The `DMPLEX`
2970: . pStart - The first mesh point
2971: - pEnd   - The upper bound for mesh points

2973:   Level: beginner

2975: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2976: @*/
2977: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2978: {
2979:   DM_Plex *mesh = (DM_Plex *)dm->data;

2981:   PetscFunctionBegin;
2983:   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
2984:   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2985:   PetscCall(PetscFree(mesh->cellTypes));
2986:   PetscFunctionReturn(PETSC_SUCCESS);
2987: }

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

2992:   Not Collective

2994:   Input Parameters:
2995: + dm - The `DMPLEX`
2996: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

2998:   Output Parameter:
2999: . size - The cone size for point `p`

3001:   Level: beginner

3003: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3004: @*/
3005: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
3006: {
3007:   DM_Plex *mesh = (DM_Plex *)dm->data;

3009:   PetscFunctionBegin;
3011:   PetscAssertPointer(size, 3);
3012:   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
3013:   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
3014:   PetscFunctionReturn(PETSC_SUCCESS);
3015: }

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

3020:   Not Collective

3022:   Input Parameters:
3023: + dm   - The `DMPLEX`
3024: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3025: - size - The cone size for point `p`

3027:   Level: beginner

3029:   Note:
3030:   This should be called after `DMPlexSetChart()`.

3032: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
3033: @*/
3034: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
3035: {
3036:   DM_Plex *mesh = (DM_Plex *)dm->data;

3038:   PetscFunctionBegin;
3040:   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
3041:   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
3042:   PetscFunctionReturn(PETSC_SUCCESS);
3043: }

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

3048:   Not Collective

3050:   Input Parameters:
3051: + dm - The `DMPLEX`
3052: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

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

3057:   Level: beginner

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

3063: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3064: @*/
3065: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3066: {
3067:   DM_Plex *mesh = (DM_Plex *)dm->data;
3068:   PetscInt off;

3070:   PetscFunctionBegin;
3072:   PetscAssertPointer(cone, 3);
3073:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3074:   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
3075:   PetscFunctionReturn(PETSC_SUCCESS);
3076: }

3078: /*@
3079:   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG

3081:   Not Collective

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

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

3091:   Level: intermediate

3093: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
3094: @*/
3095: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
3096: {
3097:   PetscSection cs, newcs;
3098:   PetscInt    *cones;
3099:   PetscInt    *newarr = NULL;
3100:   PetscInt     n;

3102:   PetscFunctionBegin;
3103:   PetscCall(DMPlexGetCones(dm, &cones));
3104:   PetscCall(DMPlexGetConeSection(dm, &cs));
3105:   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
3106:   if (pConesSection) *pConesSection = newcs;
3107:   if (pCones) {
3108:     PetscCall(PetscSectionGetStorageSize(newcs, &n));
3109:     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
3110:   }
3111:   PetscFunctionReturn(PETSC_SUCCESS);
3112: }

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

3117:   Not Collective

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

3123:   Output Parameter:
3124: . expandedPoints - An array of vertices recursively expanded from input points

3126:   Level: advanced

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

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

3133: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3134:           `DMPlexGetDepth()`, `IS`
3135: @*/
3136: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3137: {
3138:   IS      *expandedPointsAll;
3139:   PetscInt depth;

3141:   PetscFunctionBegin;
3144:   PetscAssertPointer(expandedPoints, 3);
3145:   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3146:   *expandedPoints = expandedPointsAll[0];
3147:   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
3148:   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3149:   PetscFunctionReturn(PETSC_SUCCESS);
3150: }

3152: /*@
3153:   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).

3155:   Not Collective

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

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

3166:   Level: advanced

3168:   Notes:
3169:   Like `DMPlexGetConeTuple()` but recursive.

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

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

3178: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3179:           `DMPlexGetDepth()`, `PetscSection`, `IS`
3180: @*/
3181: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3182: {
3183:   const PetscInt *arr0 = NULL, *cone = NULL;
3184:   PetscInt       *arr = NULL, *newarr = NULL;
3185:   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3186:   IS             *expandedPoints_;
3187:   PetscSection   *sections_;

3189:   PetscFunctionBegin;
3192:   if (depth) PetscAssertPointer(depth, 3);
3193:   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
3194:   if (sections) PetscAssertPointer(sections, 5);
3195:   PetscCall(ISGetLocalSize(points, &n));
3196:   PetscCall(ISGetIndices(points, &arr0));
3197:   PetscCall(DMPlexGetDepth(dm, &depth_));
3198:   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
3199:   PetscCall(PetscCalloc1(depth_, &sections_));
3200:   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3201:   for (d = depth_ - 1; d >= 0; d--) {
3202:     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
3203:     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3204:     for (i = 0; i < n; i++) {
3205:       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3206:       if (arr[i] >= start && arr[i] < end) {
3207:         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
3208:         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3209:       } else {
3210:         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3211:       }
3212:     }
3213:     PetscCall(PetscSectionSetUp(sections_[d]));
3214:     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
3215:     PetscCall(PetscMalloc1(newn, &newarr));
3216:     for (i = 0; i < n; i++) {
3217:       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
3218:       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3219:       if (cn > 1) {
3220:         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3221:         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3222:       } else {
3223:         newarr[co] = arr[i];
3224:       }
3225:     }
3226:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3227:     arr = newarr;
3228:     n   = newn;
3229:   }
3230:   PetscCall(ISRestoreIndices(points, &arr0));
3231:   *depth = depth_;
3232:   if (expandedPoints) *expandedPoints = expandedPoints_;
3233:   else {
3234:     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
3235:     PetscCall(PetscFree(expandedPoints_));
3236:   }
3237:   if (sections) *sections = sections_;
3238:   else {
3239:     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
3240:     PetscCall(PetscFree(sections_));
3241:   }
3242:   PetscFunctionReturn(PETSC_SUCCESS);
3243: }

3245: /*@
3246:   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`

3248:   Not Collective

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

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

3259:   Level: advanced

3261:   Note:
3262:   See `DMPlexGetConeRecursive()`

3264: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3265:           `DMPlexGetDepth()`, `IS`, `PetscSection`
3266: @*/
3267: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3268: {
3269:   PetscInt d, depth_;

3271:   PetscFunctionBegin;
3272:   PetscCall(DMPlexGetDepth(dm, &depth_));
3273:   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3274:   if (depth) *depth = 0;
3275:   if (expandedPoints) {
3276:     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
3277:     PetscCall(PetscFree(*expandedPoints));
3278:   }
3279:   if (sections) {
3280:     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
3281:     PetscCall(PetscFree(*sections));
3282:   }
3283:   PetscFunctionReturn(PETSC_SUCCESS);
3284: }

3286: /*@
3287:   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

3289:   Not Collective

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

3296:   Level: beginner

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

3301: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3302: @*/
3303: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3304: {
3305:   DM_Plex *mesh = (DM_Plex *)dm->data;
3306:   PetscInt dof, off, c;

3308:   PetscFunctionBegin;
3310:   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3311:   if (dof) PetscAssertPointer(cone, 3);
3312:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3313:   if (PetscDefined(USE_DEBUG)) {
3314:     PetscInt pStart, pEnd;
3315:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3316:     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);
3317:     for (c = 0; c < dof; ++c) {
3318:       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);
3319:       mesh->cones[off + c] = cone[c];
3320:     }
3321:   } else {
3322:     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3323:   }
3324:   PetscFunctionReturn(PETSC_SUCCESS);
3325: }

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

3330:   Not Collective

3332:   Input Parameters:
3333: + dm - The `DMPLEX`
3334: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

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

3340:   Level: beginner

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

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

3352: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3353: @*/
3354: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3355: {
3356:   DM_Plex *mesh = (DM_Plex *)dm->data;
3357:   PetscInt off;

3359:   PetscFunctionBegin;
3361:   if (PetscDefined(USE_DEBUG)) {
3362:     PetscInt dof;
3363:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3364:     if (dof) PetscAssertPointer(coneOrientation, 3);
3365:   }
3366:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));

3368:   *coneOrientation = &mesh->coneOrientations[off];
3369:   PetscFunctionReturn(PETSC_SUCCESS);
3370: }

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

3375:   Not Collective

3377:   Input Parameters:
3378: + dm              - The `DMPLEX`
3379: . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3380: - coneOrientation - An array of orientations

3382:   Level: beginner

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

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

3389: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3390: @*/
3391: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3392: {
3393:   DM_Plex *mesh = (DM_Plex *)dm->data;
3394:   PetscInt pStart, pEnd;
3395:   PetscInt dof, off, c;

3397:   PetscFunctionBegin;
3399:   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3400:   if (dof) PetscAssertPointer(coneOrientation, 3);
3401:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3402:   if (PetscDefined(USE_DEBUG)) {
3403:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3404:     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);
3405:     for (c = 0; c < dof; ++c) {
3406:       PetscInt cdof, o = coneOrientation[c];

3408:       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
3409:       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);
3410:       mesh->coneOrientations[off + c] = o;
3411:     }
3412:   } else {
3413:     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3414:   }
3415:   PetscFunctionReturn(PETSC_SUCCESS);
3416: }

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

3421:   Not Collective

3423:   Input Parameters:
3424: + dm        - The `DMPLEX`
3425: . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
3426: . conePos   - The local index in the cone where the point should be put
3427: - conePoint - The mesh point to insert

3429:   Level: beginner

3431: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3432: @*/
3433: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3434: {
3435:   DM_Plex *mesh = (DM_Plex *)dm->data;
3436:   PetscInt pStart, pEnd;
3437:   PetscInt dof, off;

3439:   PetscFunctionBegin;
3441:   if (PetscDefined(USE_DEBUG)) {
3442:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3443:     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);
3444:     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);
3445:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3446:     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);
3447:   }
3448:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3449:   mesh->cones[off + conePos] = conePoint;
3450:   PetscFunctionReturn(PETSC_SUCCESS);
3451: }

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

3456:   Not Collective

3458:   Input Parameters:
3459: + dm              - The `DMPLEX`
3460: . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3461: . conePos         - The local index in the cone where the point should be put
3462: - coneOrientation - The point orientation to insert

3464:   Level: beginner

3466:   Note:
3467:   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.

3469: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3470: @*/
3471: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3472: {
3473:   DM_Plex *mesh = (DM_Plex *)dm->data;
3474:   PetscInt pStart, pEnd;
3475:   PetscInt dof, off;

3477:   PetscFunctionBegin;
3479:   if (PetscDefined(USE_DEBUG)) {
3480:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3481:     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);
3482:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3483:     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);
3484:   }
3485:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3486:   mesh->coneOrientations[off + conePos] = coneOrientation;
3487:   PetscFunctionReturn(PETSC_SUCCESS);
3488: }

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

3493:   Not collective

3495:   Input Parameters:
3496: + dm - The DMPlex
3497: - p  - The point, which must lie in the chart set with DMPlexSetChart()

3499:   Output Parameters:
3500: + cone - An array of points which are on the in-edges for point `p`
3501: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3502:         integer giving the prescription for cone traversal.

3504:   Level: beginner

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

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

3516: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3517: @*/
3518: PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3519: {
3520:   DM_Plex *mesh = (DM_Plex *)dm->data;

3522:   PetscFunctionBegin;
3524:   if (mesh->tr) {
3525:     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
3526:   } else {
3527:     PetscInt off;
3528:     if (PetscDefined(USE_DEBUG)) {
3529:       PetscInt dof;
3530:       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3531:       if (dof) {
3532:         if (cone) PetscAssertPointer(cone, 3);
3533:         if (ornt) PetscAssertPointer(ornt, 4);
3534:       }
3535:     }
3536:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3537:     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
3538:     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
3539:   }
3540:   PetscFunctionReturn(PETSC_SUCCESS);
3541: }

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

3546:   Not Collective

3548:   Input Parameters:
3549: + dm   - The DMPlex
3550: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3551: . cone - An array of points which are on the in-edges for point p
3552: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3553:         integer giving the prescription for cone traversal.

3555:   Level: beginner

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

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

3567: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3568: @*/
3569: PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3570: {
3571:   DM_Plex *mesh = (DM_Plex *)dm->data;

3573:   PetscFunctionBegin;
3575:   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
3576:   PetscFunctionReturn(PETSC_SUCCESS);
3577: }

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

3582:   Not Collective

3584:   Input Parameters:
3585: + dm - The `DMPLEX`
3586: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

3588:   Output Parameter:
3589: . size - The support size for point `p`

3591:   Level: beginner

3593: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3594: @*/
3595: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3596: {
3597:   DM_Plex *mesh = (DM_Plex *)dm->data;

3599:   PetscFunctionBegin;
3601:   PetscAssertPointer(size, 3);
3602:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3603:   PetscFunctionReturn(PETSC_SUCCESS);
3604: }

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

3609:   Not Collective

3611:   Input Parameters:
3612: + dm   - The `DMPLEX`
3613: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3614: - size - The support size for point `p`

3616:   Level: beginner

3618:   Note:
3619:   This should be called after `DMPlexSetChart()`.

3621: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3622: @*/
3623: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3624: {
3625:   DM_Plex *mesh = (DM_Plex *)dm->data;

3627:   PetscFunctionBegin;
3629:   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3630:   PetscFunctionReturn(PETSC_SUCCESS);
3631: }

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

3636:   Not Collective

3638:   Input Parameters:
3639: + dm - The `DMPLEX`
3640: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

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

3645:   Level: beginner

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

3651: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3652: @*/
3653: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3654: {
3655:   DM_Plex *mesh = (DM_Plex *)dm->data;
3656:   PetscInt off;

3658:   PetscFunctionBegin;
3660:   PetscAssertPointer(support, 3);
3661:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3662:   *support = PetscSafePointerPlusOffset(mesh->supports, off);
3663:   PetscFunctionReturn(PETSC_SUCCESS);
3664: }

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

3669:   Not Collective

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

3676:   Level: beginner

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

3681: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3682: @*/
3683: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3684: {
3685:   DM_Plex *mesh = (DM_Plex *)dm->data;
3686:   PetscInt pStart, pEnd;
3687:   PetscInt dof, off, c;

3689:   PetscFunctionBegin;
3691:   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3692:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3693:   if (dof) PetscAssertPointer(support, 3);
3694:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3695:   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);
3696:   for (c = 0; c < dof; ++c) {
3697:     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);
3698:     mesh->supports[off + c] = support[c];
3699:   }
3700:   PetscFunctionReturn(PETSC_SUCCESS);
3701: }

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

3706:   Not Collective

3708:   Input Parameters:
3709: + dm           - The `DMPLEX`
3710: . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
3711: . supportPos   - The local index in the cone where the point should be put
3712: - supportPoint - The mesh point to insert

3714:   Level: beginner

3716: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3717: @*/
3718: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3719: {
3720:   DM_Plex *mesh = (DM_Plex *)dm->data;
3721:   PetscInt pStart, pEnd;
3722:   PetscInt dof, off;

3724:   PetscFunctionBegin;
3726:   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3727:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3728:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3729:   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);
3730:   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);
3731:   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);
3732:   mesh->supports[off + supportPos] = supportPoint;
3733:   PetscFunctionReturn(PETSC_SUCCESS);
3734: }

3736: /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3737: PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3738: {
3739:   switch (ct) {
3740:   case DM_POLYTOPE_SEGMENT:
3741:     if (o == -1) return -2;
3742:     break;
3743:   case DM_POLYTOPE_TRIANGLE:
3744:     if (o == -3) return -1;
3745:     if (o == -2) return -3;
3746:     if (o == -1) return -2;
3747:     break;
3748:   case DM_POLYTOPE_QUADRILATERAL:
3749:     if (o == -4) return -2;
3750:     if (o == -3) return -1;
3751:     if (o == -2) return -4;
3752:     if (o == -1) return -3;
3753:     break;
3754:   default:
3755:     return o;
3756:   }
3757:   return o;
3758: }

3760: /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3761: PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3762: {
3763:   switch (ct) {
3764:   case DM_POLYTOPE_SEGMENT:
3765:     if ((o == -2) || (o == 1)) return -1;
3766:     if (o == -1) return 0;
3767:     break;
3768:   case DM_POLYTOPE_TRIANGLE:
3769:     if (o == -3) return -2;
3770:     if (o == -2) return -1;
3771:     if (o == -1) return -3;
3772:     break;
3773:   case DM_POLYTOPE_QUADRILATERAL:
3774:     if (o == -4) return -2;
3775:     if (o == -3) return -1;
3776:     if (o == -2) return -4;
3777:     if (o == -1) return -3;
3778:     break;
3779:   default:
3780:     return o;
3781:   }
3782:   return o;
3783: }

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

3790:   PetscFunctionBegin;
3791:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3792:   for (p = pStart; p < pEnd; ++p) {
3793:     const PetscInt *cone, *ornt;
3794:     PetscInt        coneSize, c;

3796:     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
3797:     PetscCall(DMPlexGetCone(dm, p, &cone));
3798:     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3799:     for (c = 0; c < coneSize; ++c) {
3800:       DMPolytopeType ct;
3801:       const PetscInt o = ornt[c];

3803:       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3804:       switch (ct) {
3805:       case DM_POLYTOPE_SEGMENT:
3806:         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3807:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3808:         break;
3809:       case DM_POLYTOPE_TRIANGLE:
3810:         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3811:         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3812:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3813:         break;
3814:       case DM_POLYTOPE_QUADRILATERAL:
3815:         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3816:         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3817:         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
3818:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3819:         break;
3820:       default:
3821:         break;
3822:       }
3823:     }
3824:   }
3825:   PetscFunctionReturn(PETSC_SUCCESS);
3826: }

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

3832:   PetscFunctionBeginHot;
3833:   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3834:     if (useCone) {
3835:       PetscCall(DMPlexGetConeSize(dm, p, size));
3836:       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
3837:     } else {
3838:       PetscCall(DMPlexGetSupportSize(dm, p, size));
3839:       PetscCall(DMPlexGetSupport(dm, p, arr));
3840:     }
3841:   } else {
3842:     if (useCone) {
3843:       const PetscSection s   = mesh->coneSection;
3844:       const PetscInt     ps  = p - s->pStart;
3845:       const PetscInt     off = s->atlasOff[ps];

3847:       *size = s->atlasDof[ps];
3848:       *arr  = mesh->cones + off;
3849:       *ornt = mesh->coneOrientations + off;
3850:     } else {
3851:       const PetscSection s   = mesh->supportSection;
3852:       const PetscInt     ps  = p - s->pStart;
3853:       const PetscInt     off = s->atlasOff[ps];

3855:       *size = s->atlasDof[ps];
3856:       *arr  = mesh->supports + off;
3857:     }
3858:   }
3859:   PetscFunctionReturn(PETSC_SUCCESS);
3860: }

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

3866:   PetscFunctionBeginHot;
3867:   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3868:     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
3869:   }
3870:   PetscFunctionReturn(PETSC_SUCCESS);
3871: }

3873: static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3874: {
3875:   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3876:   PetscInt       *closure;
3877:   const PetscInt *tmp = NULL, *tmpO = NULL;
3878:   PetscInt        off = 0, tmpSize, t;

3880:   PetscFunctionBeginHot;
3881:   if (ornt) {
3882:     PetscCall(DMPlexGetCellType(dm, p, &ct));
3883:     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;
3884:   }
3885:   if (*points) {
3886:     closure = *points;
3887:   } else {
3888:     PetscInt maxConeSize, maxSupportSize;
3889:     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3890:     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3891:   }
3892:   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3893:   if (ct == DM_POLYTOPE_UNKNOWN) {
3894:     closure[off++] = p;
3895:     closure[off++] = 0;
3896:     for (t = 0; t < tmpSize; ++t) {
3897:       closure[off++] = tmp[t];
3898:       closure[off++] = tmpO ? tmpO[t] : 0;
3899:     }
3900:   } else {
3901:     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);

3903:     /* We assume that cells with a valid type have faces with a valid type */
3904:     closure[off++] = p;
3905:     closure[off++] = ornt;
3906:     for (t = 0; t < tmpSize; ++t) {
3907:       DMPolytopeType ft;

3909:       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3910:       closure[off++] = tmp[arr[t]];
3911:       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3912:     }
3913:   }
3914:   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3915:   if (numPoints) *numPoints = tmpSize + 1;
3916:   if (points) *points = closure;
3917:   PetscFunctionReturn(PETSC_SUCCESS);
3918: }

3920: /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3921: static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3922: {
3923:   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
3924:   const PetscInt *cone, *ornt;
3925:   PetscInt       *pts, *closure = NULL;
3926:   DMPolytopeType  ft;
3927:   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3928:   PetscInt        dim, coneSize, c, d, clSize, cl;

3930:   PetscFunctionBeginHot;
3931:   PetscCall(DMGetDimension(dm, &dim));
3932:   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3933:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3934:   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3935:   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3936:   maxSize       = PetscMax(coneSeries, supportSeries);
3937:   if (*points) {
3938:     pts = *points;
3939:   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3940:   c        = 0;
3941:   pts[c++] = point;
3942:   pts[c++] = o;
3943:   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
3944:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
3945:   for (cl = 0; cl < clSize * 2; cl += 2) {
3946:     pts[c++] = closure[cl];
3947:     pts[c++] = closure[cl + 1];
3948:   }
3949:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
3950:   for (cl = 0; cl < clSize * 2; cl += 2) {
3951:     pts[c++] = closure[cl];
3952:     pts[c++] = closure[cl + 1];
3953:   }
3954:   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3955:   for (d = 2; d < coneSize; ++d) {
3956:     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3957:     pts[c++] = cone[arr[d * 2 + 0]];
3958:     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3959:   }
3960:   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3961:   if (dim >= 3) {
3962:     for (d = 2; d < coneSize; ++d) {
3963:       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3964:       const PetscInt *fcone, *fornt;
3965:       PetscInt        fconeSize, fc, i;

3967:       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3968:       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
3969:       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3970:       for (fc = 0; fc < fconeSize; ++fc) {
3971:         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3972:         const PetscInt co = farr[fc * 2 + 1];

3974:         for (i = 0; i < c; i += 2)
3975:           if (pts[i] == cp) break;
3976:         if (i == c) {
3977:           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3978:           pts[c++] = cp;
3979:           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3980:         }
3981:       }
3982:       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3983:     }
3984:   }
3985:   *numPoints = c / 2;
3986:   *points    = pts;
3987:   PetscFunctionReturn(PETSC_SUCCESS);
3988: }

3990: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3991: {
3992:   DMPolytopeType ct;
3993:   PetscInt      *closure, *fifo;
3994:   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3995:   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3996:   PetscInt       depth, maxSize;

3998:   PetscFunctionBeginHot;
3999:   PetscCall(DMPlexGetDepth(dm, &depth));
4000:   if (depth == 1) {
4001:     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
4002:     PetscFunctionReturn(PETSC_SUCCESS);
4003:   }
4004:   PetscCall(DMPlexGetCellType(dm, p, &ct));
4005:   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;
4006:   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
4007:     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
4008:     PetscFunctionReturn(PETSC_SUCCESS);
4009:   }
4010:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4011:   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
4012:   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
4013:   maxSize       = PetscMax(coneSeries, supportSeries);
4014:   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4015:   if (*points) {
4016:     closure = *points;
4017:   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
4018:   closure[closureSize++] = p;
4019:   closure[closureSize++] = ornt;
4020:   fifo[fifoSize++]       = p;
4021:   fifo[fifoSize++]       = ornt;
4022:   fifo[fifoSize++]       = ct;
4023:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
4024:   while (fifoSize - fifoStart) {
4025:     const PetscInt       q    = fifo[fifoStart++];
4026:     const PetscInt       o    = fifo[fifoStart++];
4027:     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
4028:     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
4029:     const PetscInt      *tmp, *tmpO = NULL;
4030:     PetscInt             tmpSize, t;

4032:     if (PetscDefined(USE_DEBUG)) {
4033:       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
4034:       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);
4035:     }
4036:     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4037:     for (t = 0; t < tmpSize; ++t) {
4038:       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4039:       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4040:       const PetscInt cp = tmp[ip];
4041:       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4042:       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4043:       PetscInt       c;

4045:       /* Check for duplicate */
4046:       for (c = 0; c < closureSize; c += 2) {
4047:         if (closure[c] == cp) break;
4048:       }
4049:       if (c == closureSize) {
4050:         closure[closureSize++] = cp;
4051:         closure[closureSize++] = co;
4052:         fifo[fifoSize++]       = cp;
4053:         fifo[fifoSize++]       = co;
4054:         fifo[fifoSize++]       = ct;
4055:       }
4056:     }
4057:     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4058:   }
4059:   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4060:   if (numPoints) *numPoints = closureSize / 2;
4061:   if (points) *points = closure;
4062:   PetscFunctionReturn(PETSC_SUCCESS);
4063: }

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

4068:   Not Collective

4070:   Input Parameters:
4071: + dm      - The `DMPLEX`
4072: . p       - The mesh point
4073: - useCone - `PETSC_TRUE` for the closure, otherwise return the star

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

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

4082:   Level: beginner

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

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

4090: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4091: @*/
4092: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4093: {
4094:   PetscFunctionBeginHot;
4096:   if (numPoints) PetscAssertPointer(numPoints, 4);
4097:   if (points) PetscAssertPointer(points, 5);
4098:   if (PetscDefined(USE_DEBUG)) {
4099:     PetscInt pStart, pEnd;
4100:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4101:     PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
4102:   }
4103:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
4104:   PetscFunctionReturn(PETSC_SUCCESS);
4105: }

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

4110:   Not Collective

4112:   Input Parameters:
4113: + dm        - The `DMPLEX`
4114: . p         - The mesh point
4115: . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
4116: . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4117: - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

4119:   Level: beginner

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

4124: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4125: @*/
4126: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4127: {
4128:   PetscFunctionBeginHot;
4130:   if (numPoints) *numPoints = 0;
4131:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
4132:   PetscFunctionReturn(PETSC_SUCCESS);
4133: }

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

4138:   Not Collective

4140:   Input Parameter:
4141: . dm - The `DMPLEX`

4143:   Output Parameters:
4144: + maxConeSize    - The maximum number of in-edges
4145: - maxSupportSize - The maximum number of out-edges

4147:   Level: beginner

4149: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4150: @*/
4151: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
4152: {
4153:   DM_Plex *mesh = (DM_Plex *)dm->data;

4155:   PetscFunctionBegin;
4157:   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
4158:   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
4159:   PetscFunctionReturn(PETSC_SUCCESS);
4160: }

4162: PetscErrorCode DMSetUp_Plex(DM dm)
4163: {
4164:   DM_Plex *mesh = (DM_Plex *)dm->data;
4165:   PetscInt size, maxSupportSize;

4167:   PetscFunctionBegin;
4169:   PetscCall(PetscSectionSetUp(mesh->coneSection));
4170:   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
4171:   PetscCall(PetscMalloc1(size, &mesh->cones));
4172:   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
4173:   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4174:   if (maxSupportSize) {
4175:     PetscCall(PetscSectionSetUp(mesh->supportSection));
4176:     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
4177:     PetscCall(PetscMalloc1(size, &mesh->supports));
4178:   }
4179:   PetscFunctionReturn(PETSC_SUCCESS);
4180: }

4182: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4183: {
4184:   PetscFunctionBegin;
4185:   if (subdm) PetscCall(DMClone(dm, subdm));
4186:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
4187:   if (subdm) (*subdm)->useNatural = dm->useNatural;
4188:   if (dm->useNatural && dm->sfMigration) {
4189:     PetscSF sfNatural;

4191:     (*subdm)->sfMigration = dm->sfMigration;
4192:     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
4193:     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4194:     (*subdm)->sfNatural = sfNatural;
4195:   }
4196:   PetscFunctionReturn(PETSC_SUCCESS);
4197: }

4199: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4200: {
4201:   PetscInt i = 0;

4203:   PetscFunctionBegin;
4204:   PetscCall(DMClone(dms[0], superdm));
4205:   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4206:   (*superdm)->useNatural = PETSC_FALSE;
4207:   for (i = 0; i < len; i++) {
4208:     if (dms[i]->useNatural && dms[i]->sfMigration) {
4209:       PetscSF sfNatural;

4211:       (*superdm)->sfMigration = dms[i]->sfMigration;
4212:       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4213:       (*superdm)->useNatural = PETSC_TRUE;
4214:       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4215:       (*superdm)->sfNatural = sfNatural;
4216:       break;
4217:     }
4218:   }
4219:   PetscFunctionReturn(PETSC_SUCCESS);
4220: }

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

4225:   Not Collective

4227:   Input Parameter:
4228: . dm - The `DMPLEX`

4230:   Level: beginner

4232:   Note:
4233:   This should be called after all calls to `DMPlexSetCone()`

4235: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4236: @*/
4237: PetscErrorCode DMPlexSymmetrize(DM dm)
4238: {
4239:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4240:   PetscInt *offsets;
4241:   PetscInt  supportSize;
4242:   PetscInt  pStart, pEnd, p;

4244:   PetscFunctionBegin;
4246:   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
4247:   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4248:   /* Calculate support sizes */
4249:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4250:   for (p = pStart; p < pEnd; ++p) {
4251:     PetscInt dof, off, c;

4253:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4254:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4255:     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4256:   }
4257:   PetscCall(PetscSectionSetUp(mesh->supportSection));
4258:   /* Calculate supports */
4259:   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
4260:   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
4261:   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4262:   for (p = pStart; p < pEnd; ++p) {
4263:     PetscInt dof, off, c;

4265:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4266:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4267:     for (c = off; c < off + dof; ++c) {
4268:       const PetscInt q = mesh->cones[c];
4269:       PetscInt       offS;

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

4273:       mesh->supports[offS + offsets[q]] = p;
4274:       ++offsets[q];
4275:     }
4276:   }
4277:   PetscCall(PetscFree(offsets));
4278:   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
4279:   PetscFunctionReturn(PETSC_SUCCESS);
4280: }

4282: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4283: {
4284:   IS stratumIS;

4286:   PetscFunctionBegin;
4287:   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
4288:   if (PetscDefined(USE_DEBUG)) {
4289:     PetscInt  qStart, qEnd, numLevels, level;
4290:     PetscBool overlap = PETSC_FALSE;
4291:     PetscCall(DMLabelGetNumValues(label, &numLevels));
4292:     for (level = 0; level < numLevels; level++) {
4293:       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4294:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
4295:         overlap = PETSC_TRUE;
4296:         break;
4297:       }
4298:     }
4299:     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);
4300:   }
4301:   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
4302:   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
4303:   PetscCall(ISDestroy(&stratumIS));
4304:   PetscFunctionReturn(PETSC_SUCCESS);
4305: }

4307: static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4308: {
4309:   PetscInt *pMin, *pMax;
4310:   PetscInt  pStart, pEnd;
4311:   PetscInt  dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT;

4313:   PetscFunctionBegin;
4314:   {
4315:     DMLabel label2;

4317:     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4318:     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4319:   }
4320:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4321:   for (PetscInt p = pStart; p < pEnd; ++p) {
4322:     DMPolytopeType ct;

4324:     PetscCall(DMPlexGetCellType(dm, p, &ct));
4325:     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4326:     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4327:   }
4328:   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4329:   for (PetscInt d = dmin; d <= dmax; ++d) {
4330:     pMin[d] = PETSC_MAX_INT;
4331:     pMax[d] = PETSC_MIN_INT;
4332:   }
4333:   for (PetscInt p = pStart; p < pEnd; ++p) {
4334:     DMPolytopeType ct;
4335:     PetscInt       d;

4337:     PetscCall(DMPlexGetCellType(dm, p, &ct));
4338:     d       = DMPolytopeTypeGetDim(ct);
4339:     pMin[d] = PetscMin(p, pMin[d]);
4340:     pMax[d] = PetscMax(p, pMax[d]);
4341:   }
4342:   for (PetscInt d = dmin; d <= dmax; ++d) {
4343:     if (pMin[d] > pMax[d]) continue;
4344:     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4345:   }
4346:   PetscCall(PetscFree2(pMin, pMax));
4347:   PetscFunctionReturn(PETSC_SUCCESS);
4348: }

4350: static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4351: {
4352:   PetscInt pStart, pEnd;
4353:   PetscInt numRoots = 0, numLeaves = 0;

4355:   PetscFunctionBegin;
4356:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4357:   {
4358:     /* Initialize roots and count leaves */
4359:     PetscInt sMin = PETSC_MAX_INT;
4360:     PetscInt sMax = PETSC_MIN_INT;
4361:     PetscInt coneSize, supportSize;

4363:     for (PetscInt p = pStart; p < pEnd; ++p) {
4364:       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4365:       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4366:       if (!coneSize && supportSize) {
4367:         sMin = PetscMin(p, sMin);
4368:         sMax = PetscMax(p, sMax);
4369:         ++numRoots;
4370:       } else if (!supportSize && coneSize) {
4371:         ++numLeaves;
4372:       } else if (!supportSize && !coneSize) {
4373:         /* Isolated points */
4374:         sMin = PetscMin(p, sMin);
4375:         sMax = PetscMax(p, sMax);
4376:       }
4377:     }
4378:     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4379:   }

4381:   if (numRoots + numLeaves == (pEnd - pStart)) {
4382:     PetscInt sMin = PETSC_MAX_INT;
4383:     PetscInt sMax = PETSC_MIN_INT;
4384:     PetscInt coneSize, supportSize;

4386:     for (PetscInt p = pStart; p < pEnd; ++p) {
4387:       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4388:       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4389:       if (!supportSize && coneSize) {
4390:         sMin = PetscMin(p, sMin);
4391:         sMax = PetscMax(p, sMax);
4392:       }
4393:     }
4394:     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4395:   } else {
4396:     PetscInt level = 0;
4397:     PetscInt qStart, qEnd;

4399:     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4400:     while (qEnd > qStart) {
4401:       PetscInt sMin = PETSC_MAX_INT;
4402:       PetscInt sMax = PETSC_MIN_INT;

4404:       for (PetscInt q = qStart; q < qEnd; ++q) {
4405:         const PetscInt *support;
4406:         PetscInt        supportSize;

4408:         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4409:         PetscCall(DMPlexGetSupport(dm, q, &support));
4410:         for (PetscInt s = 0; s < supportSize; ++s) {
4411:           sMin = PetscMin(support[s], sMin);
4412:           sMax = PetscMax(support[s], sMax);
4413:         }
4414:       }
4415:       PetscCall(DMLabelGetNumValues(label, &level));
4416:       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4417:       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4418:     }
4419:   }
4420:   PetscFunctionReturn(PETSC_SUCCESS);
4421: }

4423: /*@
4424:   DMPlexStratify - Computes the strata for all points in the `DMPLEX`

4426:   Collective

4428:   Input Parameter:
4429: . dm - The `DMPLEX`

4431:   Level: beginner

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

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

4445:   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4446:   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4447:   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
4448:   to interpolate only that one (e0), so that
4449: .vb
4450:   cone(c0) = {e0, v2}
4451:   cone(e0) = {v0, v1}
4452: .ve
4453:   If `DMPlexStratify()` is run on this mesh, it will give depths
4454: .vb
4455:    depth 0 = {v0, v1, v2}
4456:    depth 1 = {e0, c0}
4457: .ve
4458:   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.

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

4462: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4463: @*/
4464: PetscErrorCode DMPlexStratify(DM dm)
4465: {
4466:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4467:   DMLabel   label;
4468:   PetscBool flg = PETSC_FALSE;

4470:   PetscFunctionBegin;
4472:   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));

4474:   // Create depth label
4475:   PetscCall(DMRemoveLabel(dm, "depth", NULL));
4476:   PetscCall(DMCreateLabel(dm, "depth"));
4477:   PetscCall(DMPlexGetDepthLabel(dm, &label));

4479:   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4480:   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4481:   else PetscCall(DMPlexStratify_Topological_Private(dm, label));

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

4486:     PetscCall(DMLabelGetNumValues(label, &numValues));
4487:     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
4488:     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4489:   }
4490:   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
4491:   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
4492:   PetscFunctionReturn(PETSC_SUCCESS);
4493: }

4495: PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4496: {
4497:   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4498:   PetscInt       dim, depth, pheight, coneSize;

4500:   PetscFunctionBeginHot;
4501:   PetscCall(DMGetDimension(dm, &dim));
4502:   PetscCall(DMPlexGetDepth(dm, &depth));
4503:   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4504:   pheight = depth - pdepth;
4505:   if (depth <= 1) {
4506:     switch (pdepth) {
4507:     case 0:
4508:       ct = DM_POLYTOPE_POINT;
4509:       break;
4510:     case 1:
4511:       switch (coneSize) {
4512:       case 2:
4513:         ct = DM_POLYTOPE_SEGMENT;
4514:         break;
4515:       case 3:
4516:         ct = DM_POLYTOPE_TRIANGLE;
4517:         break;
4518:       case 4:
4519:         switch (dim) {
4520:         case 2:
4521:           ct = DM_POLYTOPE_QUADRILATERAL;
4522:           break;
4523:         case 3:
4524:           ct = DM_POLYTOPE_TETRAHEDRON;
4525:           break;
4526:         default:
4527:           break;
4528:         }
4529:         break;
4530:       case 5:
4531:         ct = DM_POLYTOPE_PYRAMID;
4532:         break;
4533:       case 6:
4534:         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4535:         break;
4536:       case 8:
4537:         ct = DM_POLYTOPE_HEXAHEDRON;
4538:         break;
4539:       default:
4540:         break;
4541:       }
4542:     }
4543:   } else {
4544:     if (pdepth == 0) {
4545:       ct = DM_POLYTOPE_POINT;
4546:     } else if (pheight == 0) {
4547:       switch (dim) {
4548:       case 1:
4549:         switch (coneSize) {
4550:         case 2:
4551:           ct = DM_POLYTOPE_SEGMENT;
4552:           break;
4553:         default:
4554:           break;
4555:         }
4556:         break;
4557:       case 2:
4558:         switch (coneSize) {
4559:         case 3:
4560:           ct = DM_POLYTOPE_TRIANGLE;
4561:           break;
4562:         case 4:
4563:           ct = DM_POLYTOPE_QUADRILATERAL;
4564:           break;
4565:         default:
4566:           break;
4567:         }
4568:         break;
4569:       case 3:
4570:         switch (coneSize) {
4571:         case 4:
4572:           ct = DM_POLYTOPE_TETRAHEDRON;
4573:           break;
4574:         case 5: {
4575:           const PetscInt *cone;
4576:           PetscInt        faceConeSize;

4578:           PetscCall(DMPlexGetCone(dm, p, &cone));
4579:           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4580:           switch (faceConeSize) {
4581:           case 3:
4582:             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4583:             break;
4584:           case 4:
4585:             ct = DM_POLYTOPE_PYRAMID;
4586:             break;
4587:           }
4588:         } break;
4589:         case 6:
4590:           ct = DM_POLYTOPE_HEXAHEDRON;
4591:           break;
4592:         default:
4593:           break;
4594:         }
4595:         break;
4596:       default:
4597:         break;
4598:       }
4599:     } else if (pheight > 0) {
4600:       switch (coneSize) {
4601:       case 2:
4602:         ct = DM_POLYTOPE_SEGMENT;
4603:         break;
4604:       case 3:
4605:         ct = DM_POLYTOPE_TRIANGLE;
4606:         break;
4607:       case 4:
4608:         ct = DM_POLYTOPE_QUADRILATERAL;
4609:         break;
4610:       default:
4611:         break;
4612:       }
4613:     }
4614:   }
4615:   *pt = ct;
4616:   PetscFunctionReturn(PETSC_SUCCESS);
4617: }

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

4622:   Collective

4624:   Input Parameter:
4625: . dm - The `DMPLEX`

4627:   Level: developer

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

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

4636: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4637: @*/
4638: PetscErrorCode DMPlexComputeCellTypes(DM dm)
4639: {
4640:   DM_Plex *mesh;
4641:   DMLabel  ctLabel;
4642:   PetscInt pStart, pEnd, p;

4644:   PetscFunctionBegin;
4646:   mesh = (DM_Plex *)dm->data;
4647:   PetscCall(DMCreateLabel(dm, "celltype"));
4648:   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
4649:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4650:   PetscCall(PetscFree(mesh->cellTypes));
4651:   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4652:   for (p = pStart; p < pEnd; ++p) {
4653:     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4654:     PetscInt       pdepth;

4656:     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
4657:     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4658:     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]);
4659:     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4660:     mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4661:   }
4662:   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
4663:   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
4664:   PetscFunctionReturn(PETSC_SUCCESS);
4665: }

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

4670:   Not Collective

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

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

4681:   Level: intermediate

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

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

4689: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4690: @*/
4691: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4692: {
4693:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4694:   PetscInt *join[2];
4695:   PetscInt  joinSize, i = 0;
4696:   PetscInt  dof, off, p, c, m;
4697:   PetscInt  maxSupportSize;

4699:   PetscFunctionBegin;
4701:   PetscAssertPointer(points, 3);
4702:   PetscAssertPointer(numCoveredPoints, 4);
4703:   PetscAssertPointer(coveredPoints, 5);
4704:   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4705:   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
4706:   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4707:   /* Copy in support of first point */
4708:   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
4709:   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4710:   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4711:   /* Check each successive support */
4712:   for (p = 1; p < numPoints; ++p) {
4713:     PetscInt newJoinSize = 0;

4715:     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
4716:     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4717:     for (c = 0; c < dof; ++c) {
4718:       const PetscInt point = mesh->supports[off + c];

4720:       for (m = 0; m < joinSize; ++m) {
4721:         if (point == join[i][m]) {
4722:           join[1 - i][newJoinSize++] = point;
4723:           break;
4724:         }
4725:       }
4726:     }
4727:     joinSize = newJoinSize;
4728:     i        = 1 - i;
4729:   }
4730:   *numCoveredPoints = joinSize;
4731:   *coveredPoints    = join[i];
4732:   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
4733:   PetscFunctionReturn(PETSC_SUCCESS);
4734: }

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

4739:   Not Collective

4741:   Input Parameters:
4742: + dm        - The `DMPLEX` object
4743: . numPoints - The number of input points for the join
4744: - points    - The input points

4746:   Output Parameters:
4747: + numCoveredPoints - The number of points in the join
4748: - coveredPoints    - The points in the join

4750:   Level: intermediate

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

4755: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4756: @*/
4757: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4758: {
4759:   PetscFunctionBegin;
4761:   if (points) PetscAssertPointer(points, 3);
4762:   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4763:   PetscAssertPointer(coveredPoints, 5);
4764:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4765:   if (numCoveredPoints) *numCoveredPoints = 0;
4766:   PetscFunctionReturn(PETSC_SUCCESS);
4767: }

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

4772:   Not Collective

4774:   Input Parameters:
4775: + dm        - The `DMPLEX` object
4776: . numPoints - The number of input points for the join
4777: - points    - The input points

4779:   Output Parameters:
4780: + numCoveredPoints - The number of points in the join
4781: - coveredPoints    - The points in the join

4783:   Level: intermediate

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

4788: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4789: @*/
4790: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4791: {
4792:   PetscInt *offsets, **closures;
4793:   PetscInt *join[2];
4794:   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
4795:   PetscInt  p, d, c, m, ms;

4797:   PetscFunctionBegin;
4799:   PetscAssertPointer(points, 3);
4800:   PetscAssertPointer(numCoveredPoints, 4);
4801:   PetscAssertPointer(coveredPoints, 5);

4803:   PetscCall(DMPlexGetDepth(dm, &depth));
4804:   PetscCall(PetscCalloc1(numPoints, &closures));
4805:   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4806:   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
4807:   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
4808:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
4809:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));

4811:   for (p = 0; p < numPoints; ++p) {
4812:     PetscInt closureSize;

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

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

4820:       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4821:       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4822:         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4823:           offsets[p * (depth + 2) + d + 1] = i;
4824:           break;
4825:         }
4826:       }
4827:       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4828:     }
4829:     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);
4830:   }
4831:   for (d = 0; d < depth + 1; ++d) {
4832:     PetscInt dof;

4834:     /* Copy in support of first point */
4835:     dof = offsets[d + 1] - offsets[d];
4836:     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4837:     /* Check each successive cone */
4838:     for (p = 1; p < numPoints && joinSize; ++p) {
4839:       PetscInt newJoinSize = 0;

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

4845:         for (m = 0; m < joinSize; ++m) {
4846:           if (point == join[i][m]) {
4847:             join[1 - i][newJoinSize++] = point;
4848:             break;
4849:           }
4850:         }
4851:       }
4852:       joinSize = newJoinSize;
4853:       i        = 1 - i;
4854:     }
4855:     if (joinSize) break;
4856:   }
4857:   *numCoveredPoints = joinSize;
4858:   *coveredPoints    = join[i];
4859:   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4860:   PetscCall(PetscFree(closures));
4861:   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4862:   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
4863:   PetscFunctionReturn(PETSC_SUCCESS);
4864: }

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

4869:   Not Collective

4871:   Input Parameters:
4872: + dm        - The `DMPLEX` object
4873: . numPoints - The number of input points for the meet
4874: - points    - The input points

4876:   Output Parameters:
4877: + numCoveringPoints - The number of points in the meet
4878: - coveringPoints    - The points in the meet

4880:   Level: intermediate

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

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

4888: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4889: @*/
4890: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4891: {
4892:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4893:   PetscInt *meet[2];
4894:   PetscInt  meetSize, i = 0;
4895:   PetscInt  dof, off, p, c, m;
4896:   PetscInt  maxConeSize;

4898:   PetscFunctionBegin;
4900:   PetscAssertPointer(points, 3);
4901:   PetscAssertPointer(numCoveringPoints, 4);
4902:   PetscAssertPointer(coveringPoints, 5);
4903:   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
4904:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
4905:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4906:   /* Copy in cone of first point */
4907:   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
4908:   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4909:   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4910:   /* Check each successive cone */
4911:   for (p = 1; p < numPoints; ++p) {
4912:     PetscInt newMeetSize = 0;

4914:     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
4915:     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4916:     for (c = 0; c < dof; ++c) {
4917:       const PetscInt point = mesh->cones[off + c];

4919:       for (m = 0; m < meetSize; ++m) {
4920:         if (point == meet[i][m]) {
4921:           meet[1 - i][newMeetSize++] = point;
4922:           break;
4923:         }
4924:       }
4925:     }
4926:     meetSize = newMeetSize;
4927:     i        = 1 - i;
4928:   }
4929:   *numCoveringPoints = meetSize;
4930:   *coveringPoints    = meet[i];
4931:   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
4932:   PetscFunctionReturn(PETSC_SUCCESS);
4933: }

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

4938:   Not Collective

4940:   Input Parameters:
4941: + dm        - The `DMPLEX` object
4942: . numPoints - The number of input points for the meet
4943: - points    - The input points

4945:   Output Parameters:
4946: + numCoveredPoints - The number of points in the meet
4947: - coveredPoints    - The points in the meet

4949:   Level: intermediate

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

4954: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4955: @*/
4956: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4957: {
4958:   PetscFunctionBegin;
4960:   if (points) PetscAssertPointer(points, 3);
4961:   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4962:   PetscAssertPointer(coveredPoints, 5);
4963:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4964:   if (numCoveredPoints) *numCoveredPoints = 0;
4965:   PetscFunctionReturn(PETSC_SUCCESS);
4966: }

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

4971:   Not Collective

4973:   Input Parameters:
4974: + dm        - The `DMPLEX` object
4975: . numPoints - The number of input points for the meet
4976: - points    - The input points

4978:   Output Parameters:
4979: + numCoveredPoints - The number of points in the meet
4980: - coveredPoints    - The points in the meet

4982:   Level: intermediate

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

4987: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4988: @*/
4989: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4990: {
4991:   PetscInt *offsets, **closures;
4992:   PetscInt *meet[2];
4993:   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
4994:   PetscInt  p, h, c, m, mc;

4996:   PetscFunctionBegin;
4998:   PetscAssertPointer(points, 3);
4999:   PetscAssertPointer(numCoveredPoints, 4);
5000:   PetscAssertPointer(coveredPoints, 5);

5002:   PetscCall(DMPlexGetDepth(dm, &height));
5003:   PetscCall(PetscMalloc1(numPoints, &closures));
5004:   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
5005:   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
5006:   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
5007:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
5008:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));

5010:   for (p = 0; p < numPoints; ++p) {
5011:     PetscInt closureSize;

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

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

5019:       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
5020:       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
5021:         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
5022:           offsets[p * (height + 2) + h + 1] = i;
5023:           break;
5024:         }
5025:       }
5026:       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
5027:     }
5028:     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);
5029:   }
5030:   for (h = 0; h < height + 1; ++h) {
5031:     PetscInt dof;

5033:     /* Copy in cone of first point */
5034:     dof = offsets[h + 1] - offsets[h];
5035:     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
5036:     /* Check each successive cone */
5037:     for (p = 1; p < numPoints && meetSize; ++p) {
5038:       PetscInt newMeetSize = 0;

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

5044:         for (m = 0; m < meetSize; ++m) {
5045:           if (point == meet[i][m]) {
5046:             meet[1 - i][newMeetSize++] = point;
5047:             break;
5048:           }
5049:         }
5050:       }
5051:       meetSize = newMeetSize;
5052:       i        = 1 - i;
5053:     }
5054:     if (meetSize) break;
5055:   }
5056:   *numCoveredPoints = meetSize;
5057:   *coveredPoints    = meet[i];
5058:   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
5059:   PetscCall(PetscFree(closures));
5060:   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
5061:   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
5062:   PetscFunctionReturn(PETSC_SUCCESS);
5063: }

5065: /*@
5066:   DMPlexEqual - Determine if two `DM` have the same topology

5068:   Not Collective

5070:   Input Parameters:
5071: + dmA - A `DMPLEX` object
5072: - dmB - A `DMPLEX` object

5074:   Output Parameter:
5075: . equal - `PETSC_TRUE` if the topologies are identical

5077:   Level: intermediate

5079:   Note:
5080:   We are not solving graph isomorphism, so we do not permute.

5082: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
5083: @*/
5084: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5085: {
5086:   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;

5088:   PetscFunctionBegin;
5091:   PetscAssertPointer(equal, 3);

5093:   *equal = PETSC_FALSE;
5094:   PetscCall(DMPlexGetDepth(dmA, &depth));
5095:   PetscCall(DMPlexGetDepth(dmB, &depthB));
5096:   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
5097:   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
5098:   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
5099:   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
5100:   for (p = pStart; p < pEnd; ++p) {
5101:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
5102:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

5104:     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
5105:     PetscCall(DMPlexGetCone(dmA, p, &cone));
5106:     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
5107:     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
5108:     PetscCall(DMPlexGetCone(dmB, p, &coneB));
5109:     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
5110:     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
5111:     for (c = 0; c < coneSize; ++c) {
5112:       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
5113:       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
5114:     }
5115:     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
5116:     PetscCall(DMPlexGetSupport(dmA, p, &support));
5117:     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
5118:     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
5119:     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
5120:     for (s = 0; s < supportSize; ++s) {
5121:       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
5122:     }
5123:   }
5124:   *equal = PETSC_TRUE;
5125:   PetscFunctionReturn(PETSC_SUCCESS);
5126: }

5128: /*@
5129:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

5131:   Not Collective

5133:   Input Parameters:
5134: + dm         - The `DMPLEX`
5135: . cellDim    - The cell dimension
5136: - numCorners - The number of vertices on a cell

5138:   Output Parameter:
5139: . numFaceVertices - The number of vertices on a face

5141:   Level: developer

5143:   Note:
5144:   Of course this can only work for a restricted set of symmetric shapes

5146: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
5147: @*/
5148: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5149: {
5150:   MPI_Comm comm;

5152:   PetscFunctionBegin;
5153:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5154:   PetscAssertPointer(numFaceVertices, 4);
5155:   switch (cellDim) {
5156:   case 0:
5157:     *numFaceVertices = 0;
5158:     break;
5159:   case 1:
5160:     *numFaceVertices = 1;
5161:     break;
5162:   case 2:
5163:     switch (numCorners) {
5164:     case 3:                 /* triangle */
5165:       *numFaceVertices = 2; /* Edge has 2 vertices */
5166:       break;
5167:     case 4:                 /* quadrilateral */
5168:       *numFaceVertices = 2; /* Edge has 2 vertices */
5169:       break;
5170:     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
5171:       *numFaceVertices = 3; /* Edge has 3 vertices */
5172:       break;
5173:     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
5174:       *numFaceVertices = 3; /* Edge has 3 vertices */
5175:       break;
5176:     default:
5177:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5178:     }
5179:     break;
5180:   case 3:
5181:     switch (numCorners) {
5182:     case 4:                 /* tetradehdron */
5183:       *numFaceVertices = 3; /* Face has 3 vertices */
5184:       break;
5185:     case 6:                 /* tet cohesive cells */
5186:       *numFaceVertices = 4; /* Face has 4 vertices */
5187:       break;
5188:     case 8:                 /* hexahedron */
5189:       *numFaceVertices = 4; /* Face has 4 vertices */
5190:       break;
5191:     case 9:                 /* tet cohesive Lagrange cells */
5192:       *numFaceVertices = 6; /* Face has 6 vertices */
5193:       break;
5194:     case 10:                /* quadratic tetrahedron */
5195:       *numFaceVertices = 6; /* Face has 6 vertices */
5196:       break;
5197:     case 12:                /* hex cohesive Lagrange cells */
5198:       *numFaceVertices = 6; /* Face has 6 vertices */
5199:       break;
5200:     case 18:                /* quadratic tet cohesive Lagrange cells */
5201:       *numFaceVertices = 6; /* Face has 6 vertices */
5202:       break;
5203:     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
5204:       *numFaceVertices = 9; /* Face has 9 vertices */
5205:       break;
5206:     default:
5207:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5208:     }
5209:     break;
5210:   default:
5211:     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5212:   }
5213:   PetscFunctionReturn(PETSC_SUCCESS);
5214: }

5216: /*@
5217:   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point

5219:   Not Collective

5221:   Input Parameter:
5222: . dm - The `DMPLEX` object

5224:   Output Parameter:
5225: . depthLabel - The `DMLabel` recording point depth

5227:   Level: developer

5229: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5230: @*/
5231: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5232: {
5233:   PetscFunctionBegin;
5235:   PetscAssertPointer(depthLabel, 2);
5236:   *depthLabel = dm->depthLabel;
5237:   PetscFunctionReturn(PETSC_SUCCESS);
5238: }

5240: /*@
5241:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

5243:   Not Collective

5245:   Input Parameter:
5246: . dm - The `DMPLEX` object

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

5251:   Level: developer

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

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

5258:   An empty mesh gives -1.

5260: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5261: @*/
5262: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5263: {
5264:   DM_Plex *mesh = (DM_Plex *)dm->data;
5265:   DMLabel  label;
5266:   PetscInt d = -1;

5268:   PetscFunctionBegin;
5270:   PetscAssertPointer(depth, 2);
5271:   if (mesh->tr) {
5272:     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
5273:   } else {
5274:     PetscCall(DMPlexGetDepthLabel(dm, &label));
5275:     // Allow missing depths
5276:     if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d));
5277:     *depth = d;
5278:   }
5279:   PetscFunctionReturn(PETSC_SUCCESS);
5280: }

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

5285:   Not Collective

5287:   Input Parameters:
5288: + dm    - The `DMPLEX` object
5289: - depth - The requested depth

5291:   Output Parameters:
5292: + start - The first point at this `depth`
5293: - end   - One beyond the last point at this `depth`

5295:   Level: developer

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

5302: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5303: @*/
5304: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5305: {
5306:   DM_Plex *mesh = (DM_Plex *)dm->data;
5307:   DMLabel  label;
5308:   PetscInt pStart, pEnd;

5310:   PetscFunctionBegin;
5312:   if (start) {
5313:     PetscAssertPointer(start, 3);
5314:     *start = 0;
5315:   }
5316:   if (end) {
5317:     PetscAssertPointer(end, 4);
5318:     *end = 0;
5319:   }
5320:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5321:   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5322:   if (depth < 0) {
5323:     if (start) *start = pStart;
5324:     if (end) *end = pEnd;
5325:     PetscFunctionReturn(PETSC_SUCCESS);
5326:   }
5327:   if (mesh->tr) {
5328:     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
5329:   } else {
5330:     PetscCall(DMPlexGetDepthLabel(dm, &label));
5331:     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5332:     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
5333:   }
5334:   PetscFunctionReturn(PETSC_SUCCESS);
5335: }

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

5340:   Not Collective

5342:   Input Parameters:
5343: + dm     - The `DMPLEX` object
5344: - height - The requested height

5346:   Output Parameters:
5347: + start - The first point at this `height`
5348: - end   - One beyond the last point at this `height`

5350:   Level: developer

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

5357: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5358: @*/
5359: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5360: {
5361:   DMLabel  label;
5362:   PetscInt depth, pStart, pEnd;

5364:   PetscFunctionBegin;
5366:   if (start) {
5367:     PetscAssertPointer(start, 3);
5368:     *start = 0;
5369:   }
5370:   if (end) {
5371:     PetscAssertPointer(end, 4);
5372:     *end = 0;
5373:   }
5374:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5375:   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5376:   if (height < 0) {
5377:     if (start) *start = pStart;
5378:     if (end) *end = pEnd;
5379:     PetscFunctionReturn(PETSC_SUCCESS);
5380:   }
5381:   PetscCall(DMPlexGetDepthLabel(dm, &label));
5382:   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
5383:   else PetscCall(DMGetDimension(dm, &depth));
5384:   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
5385:   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
5386:   PetscFunctionReturn(PETSC_SUCCESS);
5387: }

5389: /*@
5390:   DMPlexGetPointDepth - Get the `depth` of a given point

5392:   Not Collective

5394:   Input Parameters:
5395: + dm    - The `DMPLEX` object
5396: - point - The point

5398:   Output Parameter:
5399: . depth - The depth of the `point`

5401:   Level: intermediate

5403: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5404: @*/
5405: PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5406: {
5407:   PetscFunctionBegin;
5409:   PetscAssertPointer(depth, 3);
5410:   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
5411:   PetscFunctionReturn(PETSC_SUCCESS);
5412: }

5414: /*@
5415:   DMPlexGetPointHeight - Get the `height` of a given point

5417:   Not Collective

5419:   Input Parameters:
5420: + dm    - The `DMPLEX` object
5421: - point - The point

5423:   Output Parameter:
5424: . height - The height of the `point`

5426:   Level: intermediate

5428: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
5429: @*/
5430: PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5431: {
5432:   PetscInt n, pDepth;

5434:   PetscFunctionBegin;
5436:   PetscAssertPointer(height, 3);
5437:   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
5438:   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
5439:   *height = n - 1 - pDepth; /* DAG depth is n-1 */
5440:   PetscFunctionReturn(PETSC_SUCCESS);
5441: }

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

5446:   Not Collective

5448:   Input Parameter:
5449: . dm - The `DMPLEX` object

5451:   Output Parameter:
5452: . celltypeLabel - The `DMLabel` recording cell polytope type

5454:   Level: developer

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

5460: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5461: @*/
5462: PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5463: {
5464:   PetscFunctionBegin;
5466:   PetscAssertPointer(celltypeLabel, 2);
5467:   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5468:   *celltypeLabel = dm->celltypeLabel;
5469:   PetscFunctionReturn(PETSC_SUCCESS);
5470: }

5472: /*@
5473:   DMPlexGetCellType - Get the polytope type of a given cell

5475:   Not Collective

5477:   Input Parameters:
5478: + dm   - The `DMPLEX` object
5479: - cell - The cell

5481:   Output Parameter:
5482: . celltype - The polytope type of the cell

5484:   Level: intermediate

5486: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5487: @*/
5488: PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5489: {
5490:   DM_Plex *mesh = (DM_Plex *)dm->data;
5491:   DMLabel  label;
5492:   PetscInt ct;

5494:   PetscFunctionBegin;
5496:   PetscAssertPointer(celltype, 3);
5497:   if (mesh->tr) {
5498:     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
5499:   } else {
5500:     PetscInt pStart, pEnd;

5502:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
5503:     if (!mesh->cellTypes) { /* XXX remove? optimize? */
5504:       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5505:       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5506:       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5507:       for (PetscInt p = pStart; p < pEnd; p++) {
5508:         PetscCall(DMLabelGetValue(label, p, &ct));
5509:         mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
5510:       }
5511:     }
5512:     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
5513:     if (PetscDefined(USE_DEBUG)) {
5514:       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5515:       PetscCall(DMLabelGetValue(label, cell, &ct));
5516:       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5517:       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
5518:     }
5519:   }
5520:   PetscFunctionReturn(PETSC_SUCCESS);
5521: }

5523: /*@
5524:   DMPlexSetCellType - Set the polytope type of a given cell

5526:   Not Collective

5528:   Input Parameters:
5529: + dm       - The `DMPLEX` object
5530: . cell     - The cell
5531: - celltype - The polytope type of the cell

5533:   Level: advanced

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

5541: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5542: @*/
5543: PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5544: {
5545:   DM_Plex *mesh = (DM_Plex *)dm->data;
5546:   DMLabel  label;
5547:   PetscInt pStart, pEnd;

5549:   PetscFunctionBegin;
5551:   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
5552:   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5553:   PetscCall(DMLabelSetValue(label, cell, celltype));
5554:   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5555:   mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
5556:   PetscFunctionReturn(PETSC_SUCCESS);
5557: }

5559: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5560: {
5561:   PetscSection section;
5562:   PetscInt     maxHeight;
5563:   const char  *prefix;

5565:   PetscFunctionBegin;
5566:   PetscCall(DMClone(dm, cdm));
5567:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5568:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5569:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
5570:   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
5571:   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
5572:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
5573:   PetscCall(DMSetLocalSection(*cdm, section));
5574:   PetscCall(PetscSectionDestroy(&section));

5576:   PetscCall(DMSetNumFields(*cdm, 1));
5577:   PetscCall(DMCreateDS(*cdm));
5578:   (*cdm)->cloneOpts = PETSC_TRUE;
5579:   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
5580:   PetscFunctionReturn(PETSC_SUCCESS);
5581: }

5583: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5584: {
5585:   Vec coordsLocal, cellCoordsLocal;
5586:   DM  coordsDM, cellCoordsDM;

5588:   PetscFunctionBegin;
5589:   *field = NULL;
5590:   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
5591:   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
5592:   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
5593:   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5594:   if (coordsLocal && coordsDM) {
5595:     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
5596:     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5597:   }
5598:   PetscFunctionReturn(PETSC_SUCCESS);
5599: }

5601: /*@
5602:   DMPlexGetConeSection - Return a section which describes the layout of cone data

5604:   Not Collective

5606:   Input Parameter:
5607: . dm - The `DMPLEX` object

5609:   Output Parameter:
5610: . section - The `PetscSection` object

5612:   Level: developer

5614: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
5615: @*/
5616: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5617: {
5618:   DM_Plex *mesh = (DM_Plex *)dm->data;

5620:   PetscFunctionBegin;
5622:   if (section) *section = mesh->coneSection;
5623:   PetscFunctionReturn(PETSC_SUCCESS);
5624: }

5626: /*@
5627:   DMPlexGetSupportSection - Return a section which describes the layout of support data

5629:   Not Collective

5631:   Input Parameter:
5632: . dm - The `DMPLEX` object

5634:   Output Parameter:
5635: . section - The `PetscSection` object

5637:   Level: developer

5639: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
5640: @*/
5641: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5642: {
5643:   DM_Plex *mesh = (DM_Plex *)dm->data;

5645:   PetscFunctionBegin;
5647:   if (section) *section = mesh->supportSection;
5648:   PetscFunctionReturn(PETSC_SUCCESS);
5649: }

5651: /*@C
5652:   DMPlexGetCones - Return cone data

5654:   Not Collective

5656:   Input Parameter:
5657: . dm - The `DMPLEX` object

5659:   Output Parameter:
5660: . cones - The cone for each point

5662:   Level: developer

5664: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
5665: @*/
5666: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5667: {
5668:   DM_Plex *mesh = (DM_Plex *)dm->data;

5670:   PetscFunctionBegin;
5672:   if (cones) *cones = mesh->cones;
5673:   PetscFunctionReturn(PETSC_SUCCESS);
5674: }

5676: /*@C
5677:   DMPlexGetConeOrientations - Return cone orientation data

5679:   Not Collective

5681:   Input Parameter:
5682: . dm - The `DMPLEX` object

5684:   Output Parameter:
5685: . coneOrientations - The array of cone orientations for all points

5687:   Level: developer

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

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

5694: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
5695: @*/
5696: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5697: {
5698:   DM_Plex *mesh = (DM_Plex *)dm->data;

5700:   PetscFunctionBegin;
5702:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5703:   PetscFunctionReturn(PETSC_SUCCESS);
5704: }

5706: /******************************** FEM Support **********************************/

5708: PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5709: {
5710:   PetscInt depth;

5712:   PetscFunctionBegin;
5713:   PetscCall(DMPlexGetDepth(plex, &depth));
5714:   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5715:   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5716:   PetscFunctionReturn(PETSC_SUCCESS);
5717: }

5719: PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
5720: {
5721:   PetscInt depth;

5723:   PetscFunctionBegin;
5724:   PetscCall(DMPlexGetDepth(plex, &depth));
5725:   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
5726:   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
5727:   PetscFunctionReturn(PETSC_SUCCESS);
5728: }

5730: /*
5731:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5732:  representing a line in the section.
5733: */
5734: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5735: {
5736:   PetscObject  obj;
5737:   PetscClassId id;
5738:   PetscFE      fe = NULL;

5740:   PetscFunctionBeginHot;
5741:   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5742:   PetscCall(DMGetField(dm, field, NULL, &obj));
5743:   PetscCall(PetscObjectGetClassId(obj, &id));
5744:   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;

5746:   if (!fe) {
5747:     /* Assume the full interpolated mesh is in the chart; lines in particular */
5748:     /* An order k SEM disc has k-1 dofs on an edge */
5749:     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
5750:     *k = *k / *Nc + 1;
5751:   } else {
5752:     PetscInt       dual_space_size, dim;
5753:     PetscDualSpace dsp;

5755:     PetscCall(DMGetDimension(dm, &dim));
5756:     PetscCall(PetscFEGetDualSpace(fe, &dsp));
5757:     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5758:     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
5759:     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
5760:     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
5761:   }
5762:   PetscFunctionReturn(PETSC_SUCCESS);
5763: }

5765: static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
5766: {
5767:   PetscFunctionBeginHot;
5768:   if (tensor) {
5769:     *dof = PetscPowInt(k + 1, dim);
5770:   } else {
5771:     switch (dim) {
5772:     case 1:
5773:       *dof = k + 1;
5774:       break;
5775:     case 2:
5776:       *dof = ((k + 1) * (k + 2)) / 2;
5777:       break;
5778:     case 3:
5779:       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
5780:       break;
5781:     default:
5782:       *dof = 0;
5783:     }
5784:   }
5785:   PetscFunctionReturn(PETSC_SUCCESS);
5786: }

5788: /*@

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

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

5799:   Example:
5800:   A typical interpolated single-quad mesh might order points as
5801: .vb
5802:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

5804:   v4 -- e6 -- v3
5805:   |           |
5806:   e7    c0    e8
5807:   |           |
5808:   v1 -- e5 -- v2
5809: .ve

5811:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5812:   dofs in the order of points, e.g.,
5813: .vb
5814:     c0 -> [0,1,2,3]
5815:     v1 -> [4]
5816:     ...
5817:     e5 -> [8, 9]
5818: .ve

5820:   which corresponds to the dofs
5821: .vb
5822:     6   10  11  7
5823:     13  2   3   15
5824:     12  0   1   14
5825:     4   8   9   5
5826: .ve

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

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

5838:   Level: developer

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

5844:   This is required to run with libCEED.

5846: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5847: @*/
5848: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5849: {
5850:   DMLabel   label;
5851:   PetscInt  dim, depth = -1, eStart = -1, Nf;
5852:   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;

5854:   PetscFunctionBegin;
5855:   PetscCall(DMGetDimension(dm, &dim));
5856:   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5857:   if (point < 0) {
5858:     PetscInt sStart, sEnd;

5860:     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5861:     point = sEnd - sStart ? sStart : point;
5862:   }
5863:   PetscCall(DMPlexGetDepthLabel(dm, &label));
5864:   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
5865:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
5866:   if (depth == 1) {
5867:     eStart = point;
5868:   } else if (depth == dim) {
5869:     const PetscInt *cone;

5871:     PetscCall(DMPlexGetCone(dm, point, &cone));
5872:     if (dim == 2) eStart = cone[0];
5873:     else if (dim == 3) {
5874:       const PetscInt *cone2;
5875:       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5876:       eStart = cone2[0];
5877:     } 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);
5878:   } 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);

5880:   PetscCall(PetscSectionGetNumFields(section, &Nf));
5881:   for (PetscInt d = 1; d <= dim; d++) {
5882:     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5883:     PetscInt *perm;

5885:     for (f = 0; f < Nf; ++f) {
5886:       PetscInt dof;

5888:       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5889:       PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f);
5890:       if (!continuous && d < dim) continue;
5891:       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
5892:       size += dof * Nc;
5893:     }
5894:     PetscCall(PetscMalloc1(size, &perm));
5895:     for (f = 0; f < Nf; ++f) {
5896:       switch (d) {
5897:       case 1:
5898:         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5899:         if (!continuous && d < dim) continue;
5900:         /*
5901:          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5902:          We want              [ vtx0; edge of length k-1; vtx1 ]
5903:          */
5904:         if (continuous) {
5905:           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
5906:           for (i = 0; i < k - 1; i++)
5907:             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5908:           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5909:           foffset = offset;
5910:         } else {
5911:           PetscInt dof;

5913:           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
5914:           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
5915:           foffset = offset;
5916:         }
5917:         break;
5918:       case 2:
5919:         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5920:         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5921:         if (!continuous && d < dim) continue;
5922:         /* The SEM order is

5924:          v_lb, {e_b}, v_rb,
5925:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5926:          v_lt, reverse {e_t}, v_rt
5927:          */
5928:         if (continuous) {
5929:           const PetscInt of   = 0;
5930:           const PetscInt oeb  = of + PetscSqr(k - 1);
5931:           const PetscInt oer  = oeb + (k - 1);
5932:           const PetscInt oet  = oer + (k - 1);
5933:           const PetscInt oel  = oet + (k - 1);
5934:           const PetscInt ovlb = oel + (k - 1);
5935:           const PetscInt ovrb = ovlb + 1;
5936:           const PetscInt ovrt = ovrb + 1;
5937:           const PetscInt ovlt = ovrt + 1;
5938:           PetscInt       o;

5940:           /* bottom */
5941:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
5942:           for (o = oeb; o < oer; ++o)
5943:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5944:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
5945:           /* middle */
5946:           for (i = 0; i < k - 1; ++i) {
5947:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
5948:             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
5949:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5950:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
5951:           }
5952:           /* top */
5953:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
5954:           for (o = oel - 1; o >= oet; --o)
5955:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5956:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
5957:           foffset = offset;
5958:         } else {
5959:           PetscInt dof;

5961:           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
5962:           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
5963:           foffset = offset;
5964:         }
5965:         break;
5966:       case 3:
5967:         /* The original hex closure is

5969:          {c,
5970:          f_b, f_t, f_f, f_b, f_r, f_l,
5971:          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5972:          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5973:          */
5974:         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
5975:         if (!continuous && d < dim) continue;
5976:         /* The SEM order is
5977:          Bottom Slice
5978:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5979:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5980:          v_blb, {e_bb}, v_brb,

5982:          Middle Slice (j)
5983:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5984:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5985:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

5987:          Top Slice
5988:          v_tlf, {e_tf}, v_trf,
5989:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5990:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5991:          */
5992:         if (continuous) {
5993:           const PetscInt oc    = 0;
5994:           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
5995:           const PetscInt oft   = ofb + PetscSqr(k - 1);
5996:           const PetscInt off   = oft + PetscSqr(k - 1);
5997:           const PetscInt ofk   = off + PetscSqr(k - 1);
5998:           const PetscInt ofr   = ofk + PetscSqr(k - 1);
5999:           const PetscInt ofl   = ofr + PetscSqr(k - 1);
6000:           const PetscInt oebl  = ofl + PetscSqr(k - 1);
6001:           const PetscInt oebb  = oebl + (k - 1);
6002:           const PetscInt oebr  = oebb + (k - 1);
6003:           const PetscInt oebf  = oebr + (k - 1);
6004:           const PetscInt oetf  = oebf + (k - 1);
6005:           const PetscInt oetr  = oetf + (k - 1);
6006:           const PetscInt oetb  = oetr + (k - 1);
6007:           const PetscInt oetl  = oetb + (k - 1);
6008:           const PetscInt oerf  = oetl + (k - 1);
6009:           const PetscInt oelf  = oerf + (k - 1);
6010:           const PetscInt oelb  = oelf + (k - 1);
6011:           const PetscInt oerb  = oelb + (k - 1);
6012:           const PetscInt ovblf = oerb + (k - 1);
6013:           const PetscInt ovblb = ovblf + 1;
6014:           const PetscInt ovbrb = ovblb + 1;
6015:           const PetscInt ovbrf = ovbrb + 1;
6016:           const PetscInt ovtlf = ovbrf + 1;
6017:           const PetscInt ovtrf = ovtlf + 1;
6018:           const PetscInt ovtrb = ovtrf + 1;
6019:           const PetscInt ovtlb = ovtrb + 1;
6020:           PetscInt       o, n;

6022:           /* Bottom Slice */
6023:           /*   bottom */
6024:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
6025:           for (o = oetf - 1; o >= oebf; --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] = ovbrf * Nc + c + foffset;
6028:           /*   middle */
6029:           for (i = 0; i < k - 1; ++i) {
6030:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
6031:             for (n = 0; n < k - 1; ++n) {
6032:               o = ofb + n * (k - 1) + i;
6033:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6034:             }
6035:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
6036:           }
6037:           /*   top */
6038:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
6039:           for (o = oebb; o < oebr; ++o)
6040:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6041:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;

6043:           /* Middle Slice */
6044:           for (j = 0; j < k - 1; ++j) {
6045:             /*   bottom */
6046:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
6047:             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
6048:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6049:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
6050:             /*   middle */
6051:             for (i = 0; i < k - 1; ++i) {
6052:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
6053:               for (n = 0; n < k - 1; ++n)
6054:                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
6055:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
6056:             }
6057:             /*   top */
6058:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
6059:             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
6060:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6061:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
6062:           }

6064:           /* Top Slice */
6065:           /*   bottom */
6066:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
6067:           for (o = oetf; o < oetr; ++o)
6068:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6069:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
6070:           /*   middle */
6071:           for (i = 0; i < k - 1; ++i) {
6072:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
6073:             for (n = 0; n < k - 1; ++n)
6074:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
6075:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
6076:           }
6077:           /*   top */
6078:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
6079:           for (o = oetl - 1; o >= oetb; --o)
6080:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
6081:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;

6083:           foffset = offset;
6084:         } else {
6085:           PetscInt dof;

6087:           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
6088:           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
6089:           foffset = offset;
6090:         }
6091:         break;
6092:       default:
6093:         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
6094:       }
6095:     }
6096:     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
6097:     /* Check permutation */
6098:     {
6099:       PetscInt *check;

6101:       PetscCall(PetscMalloc1(size, &check));
6102:       for (i = 0; i < size; ++i) {
6103:         check[i] = -1;
6104:         PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);
6105:       }
6106:       for (i = 0; i < size; ++i) check[perm[i]] = i;
6107:       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
6108:       PetscCall(PetscFree(check));
6109:     }
6110:     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6111:     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6112:       PetscInt *loc_perm;
6113:       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6114:       for (PetscInt i = 0; i < size; i++) {
6115:         loc_perm[i]        = perm[i];
6116:         loc_perm[size + i] = size + perm[i];
6117:       }
6118:       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6119:     }
6120:   }
6121:   PetscFunctionReturn(PETSC_SUCCESS);
6122: }

6124: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6125: {
6126:   PetscDS  prob;
6127:   PetscInt depth, Nf, h;
6128:   DMLabel  label;

6130:   PetscFunctionBeginHot;
6131:   PetscCall(DMGetDS(dm, &prob));
6132:   Nf      = prob->Nf;
6133:   label   = dm->depthLabel;
6134:   *dspace = NULL;
6135:   if (field < Nf) {
6136:     PetscObject disc = prob->disc[field];

6138:     if (disc->classid == PETSCFE_CLASSID) {
6139:       PetscDualSpace dsp;

6141:       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
6142:       PetscCall(DMLabelGetNumValues(label, &depth));
6143:       PetscCall(DMLabelGetValue(label, point, &h));
6144:       h = depth - 1 - h;
6145:       if (h) {
6146:         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6147:       } else {
6148:         *dspace = dsp;
6149:       }
6150:     }
6151:   }
6152:   PetscFunctionReturn(PETSC_SUCCESS);
6153: }

6155: static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6156: {
6157:   PetscScalar       *array;
6158:   const PetscScalar *vArray;
6159:   const PetscInt    *cone, *coneO;
6160:   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;

6162:   PetscFunctionBeginHot;
6163:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6164:   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6165:   PetscCall(DMPlexGetCone(dm, point, &cone));
6166:   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6167:   if (!values || !*values) {
6168:     if ((point >= pStart) && (point < pEnd)) {
6169:       PetscInt dof;

6171:       PetscCall(PetscSectionGetDof(section, point, &dof));
6172:       size += dof;
6173:     }
6174:     for (p = 0; p < numPoints; ++p) {
6175:       const PetscInt cp = cone[p];
6176:       PetscInt       dof;

6178:       if ((cp < pStart) || (cp >= pEnd)) continue;
6179:       PetscCall(PetscSectionGetDof(section, cp, &dof));
6180:       size += dof;
6181:     }
6182:     if (!values) {
6183:       if (csize) *csize = size;
6184:       PetscFunctionReturn(PETSC_SUCCESS);
6185:     }
6186:     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6187:   } else {
6188:     array = *values;
6189:   }
6190:   size = 0;
6191:   PetscCall(VecGetArrayRead(v, &vArray));
6192:   if ((point >= pStart) && (point < pEnd)) {
6193:     PetscInt           dof, off, d;
6194:     const PetscScalar *varr;

6196:     PetscCall(PetscSectionGetDof(section, point, &dof));
6197:     PetscCall(PetscSectionGetOffset(section, point, &off));
6198:     varr = PetscSafePointerPlusOffset(vArray, off);
6199:     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
6200:     size += dof;
6201:   }
6202:   for (p = 0; p < numPoints; ++p) {
6203:     const PetscInt     cp = cone[p];
6204:     PetscInt           o  = coneO[p];
6205:     PetscInt           dof, off, d;
6206:     const PetscScalar *varr;

6208:     if ((cp < pStart) || (cp >= pEnd)) continue;
6209:     PetscCall(PetscSectionGetDof(section, cp, &dof));
6210:     PetscCall(PetscSectionGetOffset(section, cp, &off));
6211:     varr = PetscSafePointerPlusOffset(vArray, off);
6212:     if (o >= 0) {
6213:       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
6214:     } else {
6215:       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
6216:     }
6217:     size += dof;
6218:   }
6219:   PetscCall(VecRestoreArrayRead(v, &vArray));
6220:   if (!*values) {
6221:     if (csize) *csize = size;
6222:     *values = array;
6223:   } else {
6224:     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6225:     *csize = size;
6226:   }
6227:   PetscFunctionReturn(PETSC_SUCCESS);
6228: }

6230: /* Compress out points not in the section */
6231: static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6232: {
6233:   const PetscInt np = *numPoints;
6234:   PetscInt       pStart, pEnd, p, q;

6236:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6237:   for (p = 0, q = 0; p < np; ++p) {
6238:     const PetscInt r = points[p * 2];
6239:     if ((r >= pStart) && (r < pEnd)) {
6240:       points[q * 2]     = r;
6241:       points[q * 2 + 1] = points[p * 2 + 1];
6242:       ++q;
6243:     }
6244:   }
6245:   *numPoints = q;
6246:   return PETSC_SUCCESS;
6247: }

6249: /* Compressed closure does not apply closure permutation */
6250: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6251: {
6252:   const PetscInt *cla = NULL;
6253:   PetscInt        np, *pts = NULL;

6255:   PetscFunctionBeginHot;
6256:   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
6257:   if (!ornt && *clPoints) {
6258:     PetscInt dof, off;

6260:     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
6261:     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
6262:     PetscCall(ISGetIndices(*clPoints, &cla));
6263:     np  = dof / 2;
6264:     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
6265:   } else {
6266:     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
6267:     PetscCall(CompressPoints_Private(section, &np, pts));
6268:   }
6269:   *numPoints = np;
6270:   *points    = pts;
6271:   *clp       = cla;
6272:   PetscFunctionReturn(PETSC_SUCCESS);
6273: }

6275: PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6276: {
6277:   PetscFunctionBeginHot;
6278:   if (!*clPoints) {
6279:     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6280:   } else {
6281:     PetscCall(ISRestoreIndices(*clPoints, clp));
6282:   }
6283:   *numPoints = 0;
6284:   *points    = NULL;
6285:   *clSec     = NULL;
6286:   *clPoints  = NULL;
6287:   *clp       = NULL;
6288:   PetscFunctionReturn(PETSC_SUCCESS);
6289: }

6291: static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
6292: {
6293:   PetscInt            offset = 0, p;
6294:   const PetscInt    **perms  = NULL;
6295:   const PetscScalar **flips  = NULL;

6297:   PetscFunctionBeginHot;
6298:   *size = 0;
6299:   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6300:   for (p = 0; p < numPoints; p++) {
6301:     const PetscInt     point = points[2 * p];
6302:     const PetscInt    *perm  = perms ? perms[p] : NULL;
6303:     const PetscScalar *flip  = flips ? flips[p] : NULL;
6304:     PetscInt           dof, off, d;
6305:     const PetscScalar *varr;

6307:     PetscCall(PetscSectionGetDof(section, point, &dof));
6308:     PetscCall(PetscSectionGetOffset(section, point, &off));
6309:     varr = PetscSafePointerPlusOffset(vArray, off);
6310:     if (clperm) {
6311:       if (perm) {
6312:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
6313:       } else {
6314:         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
6315:       }
6316:       if (flip) {
6317:         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
6318:       }
6319:     } else {
6320:       if (perm) {
6321:         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
6322:       } else {
6323:         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
6324:       }
6325:       if (flip) {
6326:         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
6327:       }
6328:     }
6329:     offset += dof;
6330:   }
6331:   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6332:   *size = offset;
6333:   PetscFunctionReturn(PETSC_SUCCESS);
6334: }

6336: 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[])
6337: {
6338:   PetscInt offset = 0, f;

6340:   PetscFunctionBeginHot;
6341:   *size = 0;
6342:   for (f = 0; f < numFields; ++f) {
6343:     PetscInt            p;
6344:     const PetscInt    **perms = NULL;
6345:     const PetscScalar **flips = NULL;

6347:     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6348:     for (p = 0; p < numPoints; p++) {
6349:       const PetscInt     point = points[2 * p];
6350:       PetscInt           fdof, foff, b;
6351:       const PetscScalar *varr;
6352:       const PetscInt    *perm = perms ? perms[p] : NULL;
6353:       const PetscScalar *flip = flips ? flips[p] : NULL;

6355:       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6356:       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6357:       varr = &vArray[foff];
6358:       if (clperm) {
6359:         if (perm) {
6360:           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
6361:         } else {
6362:           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
6363:         }
6364:         if (flip) {
6365:           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
6366:         }
6367:       } else {
6368:         if (perm) {
6369:           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
6370:         } else {
6371:           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
6372:         }
6373:         if (flip) {
6374:           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
6375:         }
6376:       }
6377:       offset += fdof;
6378:     }
6379:     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6380:   }
6381:   *size = offset;
6382:   PetscFunctionReturn(PETSC_SUCCESS);
6383: }

6385: PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
6386: {
6387:   PetscSection    clSection;
6388:   IS              clPoints;
6389:   PetscInt       *points = NULL;
6390:   const PetscInt *clp, *perm = NULL;
6391:   PetscInt        depth, numFields, numPoints, asize;

6393:   PetscFunctionBeginHot;
6395:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6398:   PetscCall(DMPlexGetDepth(dm, &depth));
6399:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6400:   if (depth == 1 && numFields < 2) {
6401:     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6402:     PetscFunctionReturn(PETSC_SUCCESS);
6403:   }
6404:   /* Get points */
6405:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
6406:   /* Get sizes */
6407:   asize = 0;
6408:   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
6409:     PetscInt dof;
6410:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
6411:     asize += dof;
6412:   }
6413:   if (values) {
6414:     const PetscScalar *vArray;
6415:     PetscInt           size;

6417:     if (*values) {
6418:       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);
6419:     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6420:     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
6421:     PetscCall(VecGetArrayRead(v, &vArray));
6422:     /* Get values */
6423:     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
6424:     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
6425:     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
6426:     /* Cleanup array */
6427:     PetscCall(VecRestoreArrayRead(v, &vArray));
6428:   }
6429:   if (csize) *csize = asize;
6430:   /* Cleanup points */
6431:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6432:   PetscFunctionReturn(PETSC_SUCCESS);
6433: }

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

6438:   Not collective

6440:   Input Parameters:
6441: + dm      - The `DM`
6442: . section - The section describing the layout in `v`, or `NULL` to use the default section
6443: . v       - The local vector
6444: - point   - The point in the `DM`

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

6451:   Level: intermediate

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

6458:   A typical use could be
6459: .vb
6460:    values = NULL;
6461:    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6462:    for (cl = 0; cl < clSize; ++cl) {
6463:      <Compute on closure>
6464:    }
6465:    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6466: .ve
6467:   or
6468: .vb
6469:    PetscMalloc1(clMaxSize, &values);
6470:    for (p = pStart; p < pEnd; ++p) {
6471:      clSize = clMaxSize;
6472:      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6473:      for (cl = 0; cl < clSize; ++cl) {
6474:        <Compute on closure>
6475:      }
6476:    }
6477:    PetscFree(values);
6478: .ve

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

6483: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6484: @*/
6485: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6486: {
6487:   PetscFunctionBeginHot;
6488:   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
6489:   PetscFunctionReturn(PETSC_SUCCESS);
6490: }

6492: PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6493: {
6494:   DMLabel            depthLabel;
6495:   PetscSection       clSection;
6496:   IS                 clPoints;
6497:   PetscScalar       *array;
6498:   const PetscScalar *vArray;
6499:   PetscInt          *points = NULL;
6500:   const PetscInt    *clp, *perm = NULL;
6501:   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;

6503:   PetscFunctionBeginHot;
6505:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6508:   PetscCall(DMPlexGetDepth(dm, &mdepth));
6509:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
6510:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6511:   if (mdepth == 1 && numFields < 2) {
6512:     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6513:     PetscFunctionReturn(PETSC_SUCCESS);
6514:   }
6515:   /* Get points */
6516:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6517:   for (clsize = 0, p = 0; p < Np; p++) {
6518:     PetscInt dof;
6519:     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6520:     clsize += dof;
6521:   }
6522:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6523:   /* Filter points */
6524:   for (p = 0; p < numPoints * 2; p += 2) {
6525:     PetscInt dep;

6527:     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6528:     if (dep != depth) continue;
6529:     points[Np * 2 + 0] = points[p];
6530:     points[Np * 2 + 1] = points[p + 1];
6531:     ++Np;
6532:   }
6533:   /* Get array */
6534:   if (!values || !*values) {
6535:     PetscInt asize = 0, dof;

6537:     for (p = 0; p < Np * 2; p += 2) {
6538:       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6539:       asize += dof;
6540:     }
6541:     if (!values) {
6542:       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6543:       if (csize) *csize = asize;
6544:       PetscFunctionReturn(PETSC_SUCCESS);
6545:     }
6546:     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6547:   } else {
6548:     array = *values;
6549:   }
6550:   PetscCall(VecGetArrayRead(v, &vArray));
6551:   /* Get values */
6552:   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
6553:   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6554:   /* Cleanup points */
6555:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6556:   /* Cleanup array */
6557:   PetscCall(VecRestoreArrayRead(v, &vArray));
6558:   if (!*values) {
6559:     if (csize) *csize = size;
6560:     *values = array;
6561:   } else {
6562:     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6563:     *csize = size;
6564:   }
6565:   PetscFunctionReturn(PETSC_SUCCESS);
6566: }

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

6571:   Not collective

6573:   Input Parameters:
6574: + dm      - The `DM`
6575: . section - The section describing the layout in `v`, or `NULL` to use the default section
6576: . v       - The local vector
6577: . point   - The point in the `DM`
6578: . csize   - The number of values in the closure, or `NULL`
6579: - values  - The array of values, which is a borrowed array and should not be freed

6581:   Level: intermediate

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

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

6589: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6590: @*/
6591: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6592: {
6593:   PetscInt size = 0;

6595:   PetscFunctionBegin;
6596:   /* Should work without recalculating size */
6597:   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6598:   *values = NULL;
6599:   PetscFunctionReturn(PETSC_SUCCESS);
6600: }

6602: static inline void add(PetscScalar *x, PetscScalar y)
6603: {
6604:   *x += y;
6605: }
6606: static inline void insert(PetscScalar *x, PetscScalar y)
6607: {
6608:   *x = y;
6609: }

6611: 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[])
6612: {
6613:   PetscInt        cdof;  /* The number of constraints on this point */
6614:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6615:   PetscScalar    *a;
6616:   PetscInt        off, cind = 0, k;

6618:   PetscFunctionBegin;
6619:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6620:   PetscCall(PetscSectionGetOffset(section, point, &off));
6621:   a = &array[off];
6622:   if (!cdof || setBC) {
6623:     if (clperm) {
6624:       if (perm) {
6625:         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6626:       } else {
6627:         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6628:       }
6629:     } else {
6630:       if (perm) {
6631:         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6632:       } else {
6633:         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6634:       }
6635:     }
6636:   } else {
6637:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6638:     if (clperm) {
6639:       if (perm) {
6640:         for (k = 0; k < dof; ++k) {
6641:           if ((cind < cdof) && (k == cdofs[cind])) {
6642:             ++cind;
6643:             continue;
6644:           }
6645:           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6646:         }
6647:       } else {
6648:         for (k = 0; k < dof; ++k) {
6649:           if ((cind < cdof) && (k == cdofs[cind])) {
6650:             ++cind;
6651:             continue;
6652:           }
6653:           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6654:         }
6655:       }
6656:     } else {
6657:       if (perm) {
6658:         for (k = 0; k < dof; ++k) {
6659:           if ((cind < cdof) && (k == cdofs[cind])) {
6660:             ++cind;
6661:             continue;
6662:           }
6663:           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6664:         }
6665:       } else {
6666:         for (k = 0; k < dof; ++k) {
6667:           if ((cind < cdof) && (k == cdofs[cind])) {
6668:             ++cind;
6669:             continue;
6670:           }
6671:           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6672:         }
6673:       }
6674:     }
6675:   }
6676:   PetscFunctionReturn(PETSC_SUCCESS);
6677: }

6679: 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[])
6680: {
6681:   PetscInt        cdof;  /* The number of constraints on this point */
6682:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6683:   PetscScalar    *a;
6684:   PetscInt        off, cind = 0, k;

6686:   PetscFunctionBegin;
6687:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6688:   PetscCall(PetscSectionGetOffset(section, point, &off));
6689:   a = &array[off];
6690:   if (cdof) {
6691:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6692:     if (clperm) {
6693:       if (perm) {
6694:         for (k = 0; k < dof; ++k) {
6695:           if ((cind < cdof) && (k == cdofs[cind])) {
6696:             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6697:             cind++;
6698:           }
6699:         }
6700:       } else {
6701:         for (k = 0; k < dof; ++k) {
6702:           if ((cind < cdof) && (k == cdofs[cind])) {
6703:             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6704:             cind++;
6705:           }
6706:         }
6707:       }
6708:     } else {
6709:       if (perm) {
6710:         for (k = 0; k < dof; ++k) {
6711:           if ((cind < cdof) && (k == cdofs[cind])) {
6712:             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6713:             cind++;
6714:           }
6715:         }
6716:       } else {
6717:         for (k = 0; k < dof; ++k) {
6718:           if ((cind < cdof) && (k == cdofs[cind])) {
6719:             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6720:             cind++;
6721:           }
6722:         }
6723:       }
6724:     }
6725:   }
6726:   PetscFunctionReturn(PETSC_SUCCESS);
6727: }

6729: 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[])
6730: {
6731:   PetscScalar    *a;
6732:   PetscInt        fdof, foff, fcdof, foffset = *offset;
6733:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6734:   PetscInt        cind = 0, b;

6736:   PetscFunctionBegin;
6737:   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6738:   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6739:   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6740:   a = &array[foff];
6741:   if (!fcdof || setBC) {
6742:     if (clperm) {
6743:       if (perm) {
6744:         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6745:       } else {
6746:         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6747:       }
6748:     } else {
6749:       if (perm) {
6750:         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6751:       } else {
6752:         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6753:       }
6754:     }
6755:   } else {
6756:     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6757:     if (clperm) {
6758:       if (perm) {
6759:         for (b = 0; b < fdof; b++) {
6760:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6761:             ++cind;
6762:             continue;
6763:           }
6764:           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6765:         }
6766:       } else {
6767:         for (b = 0; b < fdof; b++) {
6768:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6769:             ++cind;
6770:             continue;
6771:           }
6772:           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6773:         }
6774:       }
6775:     } else {
6776:       if (perm) {
6777:         for (b = 0; b < fdof; b++) {
6778:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6779:             ++cind;
6780:             continue;
6781:           }
6782:           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6783:         }
6784:       } else {
6785:         for (b = 0; b < fdof; b++) {
6786:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6787:             ++cind;
6788:             continue;
6789:           }
6790:           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6791:         }
6792:       }
6793:     }
6794:   }
6795:   *offset += fdof;
6796:   PetscFunctionReturn(PETSC_SUCCESS);
6797: }

6799: 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[])
6800: {
6801:   PetscScalar    *a;
6802:   PetscInt        fdof, foff, fcdof, foffset = *offset;
6803:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6804:   PetscInt        Nc, cind = 0, ncind = 0, b;
6805:   PetscBool       ncSet, fcSet;

6807:   PetscFunctionBegin;
6808:   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
6809:   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6810:   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6811:   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6812:   a = &array[foff];
6813:   if (fcdof) {
6814:     /* We just override fcdof and fcdofs with Ncc and comps */
6815:     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6816:     if (clperm) {
6817:       if (perm) {
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 + perm[b]]] * (flip ? flip[perm[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 + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6835:               ++cind;
6836:             }
6837:           }
6838:         }
6839:       } else {
6840:         if (comps) {
6841:           for (b = 0; b < fdof; b++) {
6842:             ncSet = fcSet = PETSC_FALSE;
6843:             if (b % Nc == comps[ncind]) {
6844:               ncind = (ncind + 1) % Ncc;
6845:               ncSet = PETSC_TRUE;
6846:             }
6847:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6848:               ++cind;
6849:               fcSet = PETSC_TRUE;
6850:             }
6851:             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6852:           }
6853:         } else {
6854:           for (b = 0; b < fdof; b++) {
6855:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6856:               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6857:               ++cind;
6858:             }
6859:           }
6860:         }
6861:       }
6862:     } else {
6863:       if (perm) {
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 + perm[b]] * (flip ? flip[perm[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 + perm[b]] * (flip ? flip[perm[b]] : 1.));
6881:               ++cind;
6882:             }
6883:           }
6884:         }
6885:       } else {
6886:         if (comps) {
6887:           for (b = 0; b < fdof; b++) {
6888:             ncSet = fcSet = PETSC_FALSE;
6889:             if (b % Nc == comps[ncind]) {
6890:               ncind = (ncind + 1) % Ncc;
6891:               ncSet = PETSC_TRUE;
6892:             }
6893:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6894:               ++cind;
6895:               fcSet = PETSC_TRUE;
6896:             }
6897:             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6898:           }
6899:         } else {
6900:           for (b = 0; b < fdof; b++) {
6901:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6902:               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6903:               ++cind;
6904:             }
6905:           }
6906:         }
6907:       }
6908:     }
6909:   }
6910:   *offset += fdof;
6911:   PetscFunctionReturn(PETSC_SUCCESS);
6912: }

6914: static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6915: {
6916:   PetscScalar    *array;
6917:   const PetscInt *cone, *coneO;
6918:   PetscInt        pStart, pEnd, p, numPoints, off, dof;

6920:   PetscFunctionBeginHot;
6921:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6922:   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6923:   PetscCall(DMPlexGetCone(dm, point, &cone));
6924:   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6925:   PetscCall(VecGetArray(v, &array));
6926:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6927:     const PetscInt cp = !p ? point : cone[p - 1];
6928:     const PetscInt o  = !p ? 0 : coneO[p - 1];

6930:     if ((cp < pStart) || (cp >= pEnd)) {
6931:       dof = 0;
6932:       continue;
6933:     }
6934:     PetscCall(PetscSectionGetDof(section, cp, &dof));
6935:     /* ADD_VALUES */
6936:     {
6937:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6938:       PetscScalar    *a;
6939:       PetscInt        cdof, coff, cind = 0, k;

6941:       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
6942:       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6943:       a = &array[coff];
6944:       if (!cdof) {
6945:         if (o >= 0) {
6946:           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6947:         } else {
6948:           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6949:         }
6950:       } else {
6951:         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6952:         if (o >= 0) {
6953:           for (k = 0; k < dof; ++k) {
6954:             if ((cind < cdof) && (k == cdofs[cind])) {
6955:               ++cind;
6956:               continue;
6957:             }
6958:             a[k] += values[off + k];
6959:           }
6960:         } else {
6961:           for (k = 0; k < dof; ++k) {
6962:             if ((cind < cdof) && (k == cdofs[cind])) {
6963:               ++cind;
6964:               continue;
6965:             }
6966:             a[k] += values[off + dof - k - 1];
6967:           }
6968:         }
6969:       }
6970:     }
6971:   }
6972:   PetscCall(VecRestoreArray(v, &array));
6973:   PetscFunctionReturn(PETSC_SUCCESS);
6974: }

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

6979:   Not collective

6981:   Input Parameters:
6982: + dm      - The `DM`
6983: . section - The section describing the layout in `v`, or `NULL` to use the default section
6984: . v       - The local vector
6985: . point   - The point in the `DM`
6986: . values  - The array of values
6987: - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6988:          where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.

6990:   Level: intermediate

6992: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
6993: @*/
6994: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6995: {
6996:   PetscSection    clSection;
6997:   IS              clPoints;
6998:   PetscScalar    *array;
6999:   PetscInt       *points = NULL;
7000:   const PetscInt *clp, *clperm = NULL;
7001:   PetscInt        depth, numFields, numPoints, p, clsize;

7003:   PetscFunctionBeginHot;
7005:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7008:   PetscCall(DMPlexGetDepth(dm, &depth));
7009:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7010:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
7011:     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
7012:     PetscFunctionReturn(PETSC_SUCCESS);
7013:   }
7014:   /* Get points */
7015:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7016:   for (clsize = 0, p = 0; p < numPoints; p++) {
7017:     PetscInt dof;
7018:     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7019:     clsize += dof;
7020:   }
7021:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7022:   /* Get array */
7023:   PetscCall(VecGetArray(v, &array));
7024:   /* Get values */
7025:   if (numFields > 0) {
7026:     PetscInt offset = 0, f;
7027:     for (f = 0; f < numFields; ++f) {
7028:       const PetscInt    **perms = NULL;
7029:       const PetscScalar **flips = NULL;

7031:       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7032:       switch (mode) {
7033:       case INSERT_VALUES:
7034:         for (p = 0; p < numPoints; p++) {
7035:           const PetscInt     point = points[2 * p];
7036:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7037:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7038:           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
7039:         }
7040:         break;
7041:       case INSERT_ALL_VALUES:
7042:         for (p = 0; p < numPoints; p++) {
7043:           const PetscInt     point = points[2 * p];
7044:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7045:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7046:           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
7047:         }
7048:         break;
7049:       case INSERT_BC_VALUES:
7050:         for (p = 0; p < numPoints; p++) {
7051:           const PetscInt     point = points[2 * p];
7052:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7053:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7054:           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
7055:         }
7056:         break;
7057:       case ADD_VALUES:
7058:         for (p = 0; p < numPoints; p++) {
7059:           const PetscInt     point = points[2 * p];
7060:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7061:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7062:           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
7063:         }
7064:         break;
7065:       case ADD_ALL_VALUES:
7066:         for (p = 0; p < numPoints; p++) {
7067:           const PetscInt     point = points[2 * p];
7068:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7069:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7070:           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
7071:         }
7072:         break;
7073:       case ADD_BC_VALUES:
7074:         for (p = 0; p < numPoints; p++) {
7075:           const PetscInt     point = points[2 * p];
7076:           const PetscInt    *perm  = perms ? perms[p] : NULL;
7077:           const PetscScalar *flip  = flips ? flips[p] : NULL;
7078:           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
7079:         }
7080:         break;
7081:       default:
7082:         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7083:       }
7084:       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7085:     }
7086:   } else {
7087:     PetscInt            dof, off;
7088:     const PetscInt    **perms = NULL;
7089:     const PetscScalar **flips = NULL;

7091:     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7092:     switch (mode) {
7093:     case INSERT_VALUES:
7094:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7095:         const PetscInt     point = points[2 * p];
7096:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7097:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7098:         PetscCall(PetscSectionGetDof(section, point, &dof));
7099:         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
7100:       }
7101:       break;
7102:     case INSERT_ALL_VALUES:
7103:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7104:         const PetscInt     point = points[2 * p];
7105:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7106:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7107:         PetscCall(PetscSectionGetDof(section, point, &dof));
7108:         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
7109:       }
7110:       break;
7111:     case INSERT_BC_VALUES:
7112:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7113:         const PetscInt     point = points[2 * p];
7114:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7115:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7116:         PetscCall(PetscSectionGetDof(section, point, &dof));
7117:         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
7118:       }
7119:       break;
7120:     case ADD_VALUES:
7121:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7122:         const PetscInt     point = points[2 * p];
7123:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7124:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7125:         PetscCall(PetscSectionGetDof(section, point, &dof));
7126:         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
7127:       }
7128:       break;
7129:     case ADD_ALL_VALUES:
7130:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7131:         const PetscInt     point = points[2 * p];
7132:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7133:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7134:         PetscCall(PetscSectionGetDof(section, point, &dof));
7135:         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
7136:       }
7137:       break;
7138:     case ADD_BC_VALUES:
7139:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
7140:         const PetscInt     point = points[2 * p];
7141:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7142:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7143:         PetscCall(PetscSectionGetDof(section, point, &dof));
7144:         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
7145:       }
7146:       break;
7147:     default:
7148:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7149:     }
7150:     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7151:   }
7152:   /* Cleanup points */
7153:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7154:   /* Cleanup array */
7155:   PetscCall(VecRestoreArray(v, &array));
7156:   PetscFunctionReturn(PETSC_SUCCESS);
7157: }

7159: /* Check whether the given point is in the label. If not, update the offset to skip this point */
7160: static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7161: {
7162:   PetscFunctionBegin;
7163:   *contains = PETSC_TRUE;
7164:   if (label) {
7165:     PetscInt fdof;

7167:     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
7168:     if (!*contains) {
7169:       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7170:       *offset += fdof;
7171:       PetscFunctionReturn(PETSC_SUCCESS);
7172:     }
7173:   }
7174:   PetscFunctionReturn(PETSC_SUCCESS);
7175: }

7177: /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7178: 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)
7179: {
7180:   PetscSection    clSection;
7181:   IS              clPoints;
7182:   PetscScalar    *array;
7183:   PetscInt       *points = NULL;
7184:   const PetscInt *clp;
7185:   PetscInt        numFields, numPoints, p;
7186:   PetscInt        offset = 0, f;

7188:   PetscFunctionBeginHot;
7190:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7193:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7194:   /* Get points */
7195:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7196:   /* Get array */
7197:   PetscCall(VecGetArray(v, &array));
7198:   /* Get values */
7199:   for (f = 0; f < numFields; ++f) {
7200:     const PetscInt    **perms = NULL;
7201:     const PetscScalar **flips = NULL;
7202:     PetscBool           contains;

7204:     if (!fieldActive[f]) {
7205:       for (p = 0; p < numPoints * 2; p += 2) {
7206:         PetscInt fdof;
7207:         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7208:         offset += fdof;
7209:       }
7210:       continue;
7211:     }
7212:     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7213:     switch (mode) {
7214:     case INSERT_VALUES:
7215:       for (p = 0; p < numPoints; p++) {
7216:         const PetscInt     point = points[2 * p];
7217:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7218:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7219:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7220:         if (!contains) continue;
7221:         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
7222:       }
7223:       break;
7224:     case INSERT_ALL_VALUES:
7225:       for (p = 0; p < numPoints; p++) {
7226:         const PetscInt     point = points[2 * p];
7227:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7228:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7229:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7230:         if (!contains) continue;
7231:         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
7232:       }
7233:       break;
7234:     case INSERT_BC_VALUES:
7235:       for (p = 0; p < numPoints; p++) {
7236:         const PetscInt     point = points[2 * p];
7237:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7238:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7239:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7240:         if (!contains) continue;
7241:         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
7242:       }
7243:       break;
7244:     case ADD_VALUES:
7245:       for (p = 0; p < numPoints; p++) {
7246:         const PetscInt     point = points[2 * p];
7247:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7248:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7249:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7250:         if (!contains) continue;
7251:         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
7252:       }
7253:       break;
7254:     case ADD_ALL_VALUES:
7255:       for (p = 0; p < numPoints; p++) {
7256:         const PetscInt     point = points[2 * p];
7257:         const PetscInt    *perm  = perms ? perms[p] : NULL;
7258:         const PetscScalar *flip  = flips ? flips[p] : NULL;
7259:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
7260:         if (!contains) continue;
7261:         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
7262:       }
7263:       break;
7264:     default:
7265:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7266:     }
7267:     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7268:   }
7269:   /* Cleanup points */
7270:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7271:   /* Cleanup array */
7272:   PetscCall(VecRestoreArray(v, &array));
7273:   PetscFunctionReturn(PETSC_SUCCESS);
7274: }

7276: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7277: {
7278:   PetscMPIInt rank;
7279:   PetscInt    i, j;

7281:   PetscFunctionBegin;
7282:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7283:   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
7284:   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
7285:   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7286:   numCIndices = numCIndices ? numCIndices : numRIndices;
7287:   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7288:   for (i = 0; i < numRIndices; i++) {
7289:     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7290:     for (j = 0; j < numCIndices; j++) {
7291: #if defined(PETSC_USE_COMPLEX)
7292:       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7293: #else
7294:       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7295: #endif
7296:     }
7297:     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7298:   }
7299:   PetscFunctionReturn(PETSC_SUCCESS);
7300: }

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

7305:   Input Parameters:
7306: + section - The section for this data layout
7307: . islocal - Is the section (and thus indices being requested) local or global?
7308: . point   - The point contributing dofs with these indices
7309: . off     - The global offset of this point
7310: . loff    - The local offset of each field
7311: . setBC   - The flag determining whether to include indices of boundary values
7312: . perm    - A permutation of the dofs on this point, or NULL
7313: - indperm - A permutation of the entire indices array, or NULL

7315:   Output Parameter:
7316: . indices - Indices for dofs on this point

7318:   Level: developer

7320:   Note: The indices could be local or global, depending on the value of 'off'.
7321: */
7322: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7323: {
7324:   PetscInt        dof;   /* The number of unknowns on this point */
7325:   PetscInt        cdof;  /* The number of constraints on this point */
7326:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7327:   PetscInt        cind = 0, k;

7329:   PetscFunctionBegin;
7330:   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7331:   PetscCall(PetscSectionGetDof(section, point, &dof));
7332:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7333:   if (!cdof || setBC) {
7334:     for (k = 0; k < dof; ++k) {
7335:       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7336:       const PetscInt ind    = indperm ? indperm[preind] : preind;

7338:       indices[ind] = off + k;
7339:     }
7340:   } else {
7341:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
7342:     for (k = 0; k < dof; ++k) {
7343:       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7344:       const PetscInt ind    = indperm ? indperm[preind] : preind;

7346:       if ((cind < cdof) && (k == cdofs[cind])) {
7347:         /* Insert check for returning constrained indices */
7348:         indices[ind] = -(off + k + 1);
7349:         ++cind;
7350:       } else {
7351:         indices[ind] = off + k - (islocal ? 0 : cind);
7352:       }
7353:     }
7354:   }
7355:   *loff += dof;
7356:   PetscFunctionReturn(PETSC_SUCCESS);
7357: }

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

7362:  Input Parameters:
7363: + section - a section (global or local)
7364: - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
7365: . point - point within section
7366: . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
7367: . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
7368: . setBC - identify constrained (boundary condition) points via involution.
7369: . perms - perms[f][permsoff][:] is a permutation of dofs within each field
7370: . permsoff - offset
7371: - indperm - index permutation

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

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

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

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

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

7396:  Level: developer
7397: */
7398: 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[])
7399: {
7400:   PetscInt numFields, foff, f;

7402:   PetscFunctionBegin;
7403:   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7404:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7405:   for (f = 0, foff = 0; f < numFields; ++f) {
7406:     PetscInt        fdof, cfdof;
7407:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7408:     PetscInt        cind = 0, b;
7409:     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

7411:     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7412:     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7413:     if (!cfdof || setBC) {
7414:       for (b = 0; b < fdof; ++b) {
7415:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7416:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7418:         indices[ind] = off + foff + b;
7419:       }
7420:     } else {
7421:       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7422:       for (b = 0; b < fdof; ++b) {
7423:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7424:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7426:         if ((cind < cfdof) && (b == fcdofs[cind])) {
7427:           indices[ind] = -(off + foff + b + 1);
7428:           ++cind;
7429:         } else {
7430:           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7431:         }
7432:       }
7433:     }
7434:     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7435:     foffs[f] += fdof;
7436:   }
7437:   PetscFunctionReturn(PETSC_SUCCESS);
7438: }

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

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

7445:  Notes:
7446:  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7447:  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
7448: */
7449: static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7450: {
7451:   PetscInt numFields, foff, f;

7453:   PetscFunctionBegin;
7454:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7455:   for (f = 0; f < numFields; ++f) {
7456:     PetscInt        fdof, cfdof;
7457:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7458:     PetscInt        cind = 0, b;
7459:     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

7461:     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7462:     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7463:     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7464:     if (!cfdof) {
7465:       for (b = 0; b < fdof; ++b) {
7466:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7467:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7469:         indices[ind] = foff + b;
7470:       }
7471:     } else {
7472:       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7473:       for (b = 0; b < fdof; ++b) {
7474:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7475:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7477:         if ((cind < cfdof) && (b == fcdofs[cind])) {
7478:           indices[ind] = -(foff + b + 1);
7479:           ++cind;
7480:         } else {
7481:           indices[ind] = foff + b - cind;
7482:         }
7483:       }
7484:     }
7485:     foffs[f] += fdof;
7486:   }
7487:   PetscFunctionReturn(PETSC_SUCCESS);
7488: }

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

7494:   PetscFunctionBegin;
7495:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7496:   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7497:   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7498:   for (PetscInt p = 0; p < nPoints; p++) {
7499:     PetscInt     b       = pnts[2 * p];
7500:     PetscInt     bSecDof = 0, bOff;
7501:     PetscInt     cSecDof = 0;
7502:     PetscSection indices_section;

7504:     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7505:     if (!bSecDof) continue;
7506:     if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof));
7507:     indices_section = cSecDof > 0 ? cSec : section;
7508:     if (numFields) {
7509:       PetscInt fStart[32], fEnd[32];

7511:       fStart[0] = 0;
7512:       fEnd[0]   = 0;
7513:       for (PetscInt f = 0; f < numFields; f++) {
7514:         PetscInt fDof = 0;

7516:         PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof));
7517:         fStart[f + 1] = fStart[f] + fDof;
7518:         fEnd[f + 1]   = fStart[f + 1];
7519:       }
7520:       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7521:       // only apply permutations on one side
7522:       PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices));
7523:       for (PetscInt f = 0; f < numFields; f++) {
7524:         for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); }
7525:       }
7526:     } else {
7527:       PetscInt bEnd = 0;

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

7532:       for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7533:     }
7534:   }
7535:   PetscFunctionReturn(PETSC_SUCCESS);
7536: }

7538: 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[])
7539: {
7540:   Mat             cMat;
7541:   PetscSection    aSec, cSec;
7542:   IS              aIS;
7543:   PetscInt        aStart = -1, aEnd = -1;
7544:   PetscInt        sStart = -1, sEnd = -1;
7545:   PetscInt        cStart = -1, cEnd = -1;
7546:   const PetscInt *anchors;
7547:   PetscInt        numFields, p;
7548:   PetscInt        newNumPoints = 0, newNumIndices = 0;
7549:   PetscInt       *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices;
7550:   PetscInt        oldOffsets[32];
7551:   PetscInt        newOffsets[32];
7552:   PetscInt        oldOffsetsCopy[32];
7553:   PetscInt        newOffsetsCopy[32];
7554:   PetscScalar    *modMat         = NULL;
7555:   PetscBool       anyConstrained = PETSC_FALSE;

7557:   PetscFunctionBegin;
7560:   PetscCall(PetscSectionGetNumFields(section, &numFields));

7562:   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7563:   /* if there are point-to-point constraints */
7564:   if (aSec) {
7565:     PetscCall(PetscArrayzero(newOffsets, 32));
7566:     PetscCall(PetscArrayzero(oldOffsets, 32));
7567:     PetscCall(ISGetIndices(aIS, &anchors));
7568:     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7569:     PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7570:     /* figure out how many points are going to be in the new element matrix
7571:      * (we allow double counting, because it's all just going to be summed
7572:      * into the global matrix anyway) */
7573:     for (p = 0; p < 2 * numPoints; p += 2) {
7574:       PetscInt b    = points[p];
7575:       PetscInt bDof = 0, bSecDof = 0;

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

7580:       for (PetscInt f = 0; f < numFields; f++) {
7581:         PetscInt fDof = 0;

7583:         PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7584:         oldOffsets[f + 1] += fDof;
7585:       }
7586:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7587:       if (bDof) {
7588:         /* this point is constrained */
7589:         /* it is going to be replaced by its anchors */
7590:         PetscInt bOff, q;

7592:         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7593:         for (q = 0; q < bDof; q++) {
7594:           PetscInt a    = anchors[bOff + q];
7595:           PetscInt aDof = 0;

7597:           if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7598:           if (aDof) {
7599:             anyConstrained = PETSC_TRUE;
7600:             newNumPoints += 1;
7601:           }
7602:           newNumIndices += aDof;
7603:           for (PetscInt f = 0; f < numFields; ++f) {
7604:             PetscInt fDof = 0;

7606:             if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7607:             newOffsets[f + 1] += fDof;
7608:           }
7609:         }
7610:       } else {
7611:         /* this point is not constrained */
7612:         newNumPoints++;
7613:         newNumIndices += bSecDof;
7614:         for (PetscInt f = 0; f < numFields; ++f) {
7615:           PetscInt fDof;

7617:           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7618:           newOffsets[f + 1] += fDof;
7619:         }
7620:       }
7621:     }
7622:   }
7623:   if (!anyConstrained) {
7624:     if (outNumPoints) *outNumPoints = 0;
7625:     if (outNumIndices) *outNumIndices = 0;
7626:     if (outPoints) *outPoints = NULL;
7627:     if (outMat) *outMat = NULL;
7628:     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7629:     PetscFunctionReturn(PETSC_SUCCESS);
7630:   }

7632:   if (outNumPoints) *outNumPoints = newNumPoints;
7633:   if (outNumIndices) *outNumIndices = newNumIndices;

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

7638:   if (!outPoints && !outMat) {
7639:     if (offsets) {
7640:       for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7641:     }
7642:     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7643:     PetscFunctionReturn(PETSC_SUCCESS);
7644:   }

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

7649:   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7650:   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));

7652:   /* output arrays */
7653:   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7654:   PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints));

7656:   // get the new Points
7657:   for (PetscInt p = 0, newP = 0; p < numPoints; p++) {
7658:     PetscInt b    = points[2 * p];
7659:     PetscInt bDof = 0, bSecDof = 0, bOff;

7661:     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7662:     if (!bSecDof) continue;
7663:     if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7664:     if (bDof) {
7665:       PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7666:       for (PetscInt q = 0; q < bDof; q++) {
7667:         PetscInt a = anchors[bOff + q], aDof = 0;

7669:         if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7670:         if (aDof) {
7671:           newPoints[2 * newP]     = a;
7672:           newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation
7673:           newP++;
7674:         }
7675:       }
7676:     } else {
7677:       newPoints[2 * newP]     = b;
7678:       newPoints[2 * newP + 1] = points[2 * p + 1];
7679:       newP++;
7680:     }
7681:   }

7683:   if (outMat) {
7684:     PetscScalar *tmpMat;
7685:     PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32));
7686:     PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32));

7688:     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices));
7689:     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7690:     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7691:     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));

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

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

7699:     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
7700:     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
7701:     PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices));
7702:     // for each field, insert the anchor modification into modMat
7703:     for (PetscInt f = 0; f < PetscMax(1, numFields); f++) {
7704:       PetscInt fStart    = oldOffsets[f];
7705:       PetscInt fNewStart = newOffsets[f];
7706:       for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) {
7707:         PetscInt b    = points[2 * p];
7708:         PetscInt bDof = 0, bSecDof = 0, bOff;

7710:         if (b >= sStart && b < sEnd) {
7711:           if (numFields) {
7712:             PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof));
7713:           } else {
7714:             PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7715:           }
7716:         }
7717:         if (!bSecDof) continue;
7718:         if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7719:         if (bDof) {
7720:           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7721:           for (PetscInt q = 0; q < bDof; q++, newP++) {
7722:             PetscInt a = anchors[bOff + q], aDof = 0;

7724:             if (a >= sStart && a < sEnd) {
7725:               if (numFields) {
7726:                 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
7727:               } else {
7728:                 PetscCall(PetscSectionGetDof(section, a, &aDof));
7729:               }
7730:             }
7731:             if (aDof) {
7732:               PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat));
7733:               for (PetscInt d = 0; d < bSecDof; d++) {
7734:                 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e];
7735:               }
7736:             }
7737:             oNew += aDof;
7738:           }
7739:         } else {
7740:           // Insert the identity matrix in this block
7741:           for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1;
7742:           oNew += bSecDof;
7743:           newP++;
7744:         }
7745:         o += bSecDof;
7746:       }
7747:     }

7749:     *outMat = modMat;

7751:     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
7752:     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7753:     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7754:     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7755:     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices));
7756:   }
7757:   PetscCall(ISRestoreIndices(aIS, &anchors));

7759:   /* output */
7760:   if (outPoints) {
7761:     *outPoints = newPoints;
7762:   } else {
7763:     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7764:   }
7765:   for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7766:   PetscFunctionReturn(PETSC_SUCCESS);
7767: }

7769: 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)
7770: {
7771:   PetscScalar *modMat        = NULL;
7772:   PetscInt     newNumIndices = -1;

7774:   PetscFunctionBegin;
7775:   /* 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.
7776:      modMat is that matrix C */
7777:   PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL));
7778:   if (outNumIndices) *outNumIndices = newNumIndices;
7779:   if (modMat) {
7780:     const PetscScalar *newValues = values;

7782:     if (multiplyRight) {
7783:       PetscScalar *newNewValues = NULL;
7784:       PetscBLASInt M            = newNumIndices;
7785:       PetscBLASInt N            = numRows;
7786:       PetscBLASInt K            = numIndices;
7787:       PetscScalar  a = 1.0, b = 0.0;

7789:       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);

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

7795:       numCols   = newNumIndices;
7796:       newValues = newNewValues;
7797:     }

7799:     if (multiplyLeft) {
7800:       PetscScalar *newNewValues = NULL;
7801:       PetscBLASInt M            = numCols;
7802:       PetscBLASInt N            = newNumIndices;
7803:       PetscBLASInt K            = numIndices;
7804:       PetscScalar  a = 1.0, b = 0.0;

7806:       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);

7808:       PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues));
7809:       // row-major to column-major conversion, left multiplication becomes right multiplication
7810:       PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M));
7811:       if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues));
7812:       newValues = newNewValues;
7813:     }
7814:     *outValues = (PetscScalar *)newValues;
7815:     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
7816:   }
7817:   PetscFunctionReturn(PETSC_SUCCESS);
7818: }

7820: 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)
7821: {
7822:   PetscFunctionBegin;
7823:   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft));
7824:   PetscFunctionReturn(PETSC_SUCCESS);
7825: }

7827: static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize)
7828: {
7829:   /* Closure ordering */
7830:   PetscSection    clSection;
7831:   IS              clPoints;
7832:   const PetscInt *clp;
7833:   PetscInt       *points;
7834:   PetscInt        Ncl, Ni = 0;

7836:   PetscFunctionBeginHot;
7837:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7838:   for (PetscInt p = 0; p < Ncl * 2; p += 2) {
7839:     PetscInt dof;

7841:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
7842:     Ni += dof;
7843:   }
7844:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7845:   *closureSize = Ni;
7846:   PetscFunctionReturn(PETSC_SUCCESS);
7847: }

7849: 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)
7850: {
7851:   /* Closure ordering */
7852:   PetscSection    clSection;
7853:   IS              clPoints;
7854:   const PetscInt *clp;
7855:   PetscInt       *points;
7856:   const PetscInt *clperm = NULL;
7857:   /* Dof permutation and sign flips */
7858:   const PetscInt    **perms[32] = {NULL};
7859:   const PetscScalar **flips[32] = {NULL};
7860:   PetscScalar        *valCopy   = NULL;
7861:   /* Hanging node constraints */
7862:   PetscInt    *pointsC = NULL;
7863:   PetscScalar *valuesC = NULL;
7864:   PetscInt     NclC, NiC;

7866:   PetscInt *idx;
7867:   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
7868:   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7869:   PetscInt  idxStart, idxEnd;
7870:   PetscInt  nRows, nCols;

7872:   PetscFunctionBeginHot;
7876:   PetscAssertPointer(numRows, 6);
7877:   PetscAssertPointer(numCols, 7);
7878:   if (indices) PetscAssertPointer(indices, 8);
7879:   if (outOffsets) PetscAssertPointer(outOffsets, 9);
7880:   if (values) PetscAssertPointer(values, 10);
7881:   PetscCall(PetscSectionGetNumFields(section, &Nf));
7882:   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
7883:   PetscCall(PetscArrayzero(offsets, 32));
7884:   /* 1) Get points in closure */
7885:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7886:   if (useClPerm) {
7887:     PetscInt depth, clsize;
7888:     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7889:     for (clsize = 0, p = 0; p < Ncl; p++) {
7890:       PetscInt dof;
7891:       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7892:       clsize += dof;
7893:     }
7894:     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7895:   }
7896:   /* 2) Get number of indices on these points and field offsets from section */
7897:   for (p = 0; p < Ncl * 2; p += 2) {
7898:     PetscInt dof, fdof;

7900:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
7901:     for (f = 0; f < Nf; ++f) {
7902:       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7903:       offsets[f + 1] += fdof;
7904:     }
7905:     Ni += dof;
7906:   }
7907:   if (*numRows == -1) *numRows = Ni;
7908:   if (*numCols == -1) *numCols = Ni;
7909:   nRows = *numRows;
7910:   nCols = *numCols;
7911:   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
7912:   PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni);
7913:   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7914:   if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols);
7915:   if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows);
7916:   for (f = 0; f < PetscMax(1, Nf); ++f) {
7917:     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7918:     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
7919:     /* may need to apply sign changes to the element matrix */
7920:     if (values && flips[f]) {
7921:       PetscInt foffset = offsets[f];

7923:       for (p = 0; p < Ncl; ++p) {
7924:         PetscInt           pnt  = points[2 * p], fdof;
7925:         const