xref: /petsc/src/dm/impls/plex/plex.c (revision 59e4dc13e98862523cb84dba7750c0c37a930a2a)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2695799ffSMatthew G. Knepley #include <petsc/private/dmlabelimpl.h>
3af0996ceSBarry Smith #include <petsc/private/isimpl.h>
4e5c6e791SKarl Rupp #include <petsc/private/vecimpl.h>
58135c375SStefano Zampini #include <petsc/private/glvisvecimpl.h>
60c312b8eSJed Brown #include <petscsf.h>
7e228b242SToby Isaac #include <petscds.h>
8e412dcbdSMatthew G. Knepley #include <petscdraw.h>
9f19dbd58SToby Isaac #include <petscdmfield.h>
10012bc364SMatthew G. Knepley #include <petscdmplextransform.h>
11552f7358SJed Brown 
12552f7358SJed Brown /* Logging support */
1302f7d72cSksagiyam 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;
14172ee266SJed Brown PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;
15552f7358SJed Brown 
165a576424SJed Brown PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
17552f7358SJed Brown 
18e5337592SStefano Zampini /*@
199318fe57SMatthew G. Knepley   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
209318fe57SMatthew G. Knepley 
219318fe57SMatthew G. Knepley   Input Parameter:
22a1cb98faSBarry Smith . dm      - The `DMPLEX` object
239318fe57SMatthew G. Knepley 
249318fe57SMatthew G. Knepley   Output Parameter:
259318fe57SMatthew G. Knepley . simplex - Flag checking for a simplex
269318fe57SMatthew G. Knepley 
279318fe57SMatthew G. Knepley   Level: intermediate
289318fe57SMatthew G. Knepley 
29a1cb98faSBarry Smith   Note:
30a1cb98faSBarry Smith   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
31a1cb98faSBarry Smith   If the mesh has no cells, this returns `PETSC_FALSE`.
32a1cb98faSBarry Smith 
331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
349318fe57SMatthew G. Knepley @*/
35d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
36d71ae5a4SJacob Faibussowitsch {
379318fe57SMatthew G. Knepley   DMPolytopeType ct;
389318fe57SMatthew G. Knepley   PetscInt       cStart, cEnd;
399318fe57SMatthew G. Knepley 
409318fe57SMatthew G. Knepley   PetscFunctionBegin;
419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
429371c9d4SSatish Balay   if (cEnd <= cStart) {
439371c9d4SSatish Balay     *simplex = PETSC_FALSE;
443ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
459371c9d4SSatish Balay   }
469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
479318fe57SMatthew G. Knepley   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
499318fe57SMatthew G. Knepley }
509318fe57SMatthew G. Knepley 
519318fe57SMatthew G. Knepley /*@
52412e9a14SMatthew G. Knepley   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
53e5337592SStefano Zampini 
54d8d19677SJose E. Roman   Input Parameters:
55a1cb98faSBarry Smith + dm     - The `DMPLEX` object
56412e9a14SMatthew G. Knepley - height - The cell height in the Plex, 0 is the default
57e5337592SStefano Zampini 
58e5337592SStefano Zampini   Output Parameters:
59412e9a14SMatthew G. Knepley + cStart - The first "normal" cell
60412e9a14SMatthew G. Knepley - cEnd   - The upper bound on "normal"" cells
61e5337592SStefano Zampini 
62412e9a14SMatthew G. Knepley   Level: developer
63e5337592SStefano Zampini 
64a1cb98faSBarry Smith   Note:
65a1cb98faSBarry Smith   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
66a1cb98faSBarry Smith 
672827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
68e5337592SStefano Zampini @*/
69d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
70d71ae5a4SJacob Faibussowitsch {
71412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
72412e9a14SMatthew G. Knepley   PetscInt       cS, cE, c;
73e5337592SStefano Zampini 
74e5337592SStefano Zampini   PetscFunctionBegin;
759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE));
76412e9a14SMatthew G. Knepley   for (c = cS; c < cE; ++c) {
77412e9a14SMatthew G. Knepley     DMPolytopeType cct;
78412e9a14SMatthew G. Knepley 
799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &cct));
80412e9a14SMatthew G. Knepley     if ((PetscInt)cct < 0) break;
81412e9a14SMatthew G. Knepley     switch (cct) {
82ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_POINT:
83ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
84ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
85ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
86ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
87d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_HEXAHEDRON:
88d71ae5a4SJacob Faibussowitsch       ct = cct;
89d71ae5a4SJacob Faibussowitsch       break;
90d71ae5a4SJacob Faibussowitsch     default:
91d71ae5a4SJacob Faibussowitsch       break;
92e5337592SStefano Zampini     }
93412e9a14SMatthew G. Knepley     if (ct != DM_POLYTOPE_UNKNOWN) break;
94e5337592SStefano Zampini   }
95412e9a14SMatthew G. Knepley   if (ct != DM_POLYTOPE_UNKNOWN) {
96412e9a14SMatthew G. Knepley     DMLabel ctLabel;
97412e9a14SMatthew G. Knepley 
989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
999566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE));
100695799ffSMatthew G. Knepley     // Reset label for fast lookup
101695799ffSMatthew G. Knepley     PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
102e5337592SStefano Zampini   }
103412e9a14SMatthew G. Knepley   if (cStart) *cStart = cS;
104412e9a14SMatthew G. Knepley   if (cEnd) *cEnd = cE;
1053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
106e5337592SStefano Zampini }
107e5337592SStefano Zampini 
108d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
109d71ae5a4SJacob Faibussowitsch {
110412e9a14SMatthew G. Knepley   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
111a99a26bcSAdrian Croucher   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
1127e42fee7SMatthew G. Knepley 
1137e42fee7SMatthew G. Knepley   PetscFunctionBegin;
114e630c359SToby Isaac   *ft = PETSC_VTK_INVALID;
1159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1197e42fee7SMatthew G. Knepley   if (field >= 0) {
1209566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
1219566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
1227e42fee7SMatthew G. Knepley   } else {
1239566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
1249566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
1257e42fee7SMatthew G. Knepley   }
126712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
127a99a26bcSAdrian Croucher   if (globalvcdof[0]) {
1287e42fee7SMatthew G. Knepley     *sStart = vStart;
1297e42fee7SMatthew G. Knepley     *sEnd   = vEnd;
130f094498dSMatthew G. Knepley     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
1317e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_POINT_FIELD;
132a99a26bcSAdrian Croucher   } else if (globalvcdof[1]) {
1337e42fee7SMatthew G. Knepley     *sStart = cStart;
1347e42fee7SMatthew G. Knepley     *sEnd   = cEnd;
135f094498dSMatthew G. Knepley     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
1367e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_CELL_FIELD;
137e630c359SToby Isaac   } else {
138e630c359SToby Isaac     if (field >= 0) {
139e630c359SToby Isaac       const char *fieldname;
140e630c359SToby Isaac 
1419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
14263a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
143e630c359SToby Isaac     } else {
14463a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
145e630c359SToby Isaac     }
146e630c359SToby Isaac   }
1473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1487e42fee7SMatthew G. Knepley }
1497e42fee7SMatthew G. Knepley 
1506913077dSMatthew G. Knepley /*@
1516913077dSMatthew G. Knepley   DMPlexVecView1D - Plot many 1D solutions on the same line graph
1526913077dSMatthew G. Knepley 
15320f4b53cSBarry Smith   Collective
1546913077dSMatthew G. Knepley 
1556913077dSMatthew G. Knepley   Input Parameters:
156a1cb98faSBarry Smith + dm - The `DMPLEX` object
1576913077dSMatthew G. Knepley . n  - The number of vectors
1586913077dSMatthew G. Knepley . u  - The array of local vectors
159a1cb98faSBarry Smith - viewer - The `PetscViewer`
1606913077dSMatthew G. Knepley 
1616913077dSMatthew G. Knepley   Level: advanced
1626913077dSMatthew G. Knepley 
1631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
1646913077dSMatthew G. Knepley @*/
165d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
166d71ae5a4SJacob Faibussowitsch {
1676913077dSMatthew G. Knepley   PetscDS            ds;
1686913077dSMatthew G. Knepley   PetscDraw          draw = NULL;
1696913077dSMatthew G. Knepley   PetscDrawLG        lg;
1706913077dSMatthew G. Knepley   Vec                coordinates;
1716913077dSMatthew G. Knepley   const PetscScalar *coords, **sol;
1726913077dSMatthew G. Knepley   PetscReal         *vals;
1736913077dSMatthew G. Knepley   PetscInt          *Nc;
1746913077dSMatthew G. Knepley   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
1756913077dSMatthew G. Knepley   char             **names;
1766913077dSMatthew G. Knepley 
1776913077dSMatthew G. Knepley   PetscFunctionBegin;
1789566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
1799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
1809566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
1819566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponents(ds, &Nc));
1826913077dSMatthew G. Knepley 
1839566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1843ba16761SJacob Faibussowitsch   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
1859566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
1866913077dSMatthew G. Knepley 
1879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
1886913077dSMatthew G. Knepley   for (i = 0, l = 0; i < n; ++i) {
1896913077dSMatthew G. Knepley     const char *vname;
1906913077dSMatthew G. Knepley 
1919566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
1926913077dSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
1936913077dSMatthew G. Knepley       PetscObject disc;
1946913077dSMatthew G. Knepley       const char *fname;
1956913077dSMatthew G. Knepley       char        tmpname[PETSC_MAX_PATH_LEN];
1966913077dSMatthew G. Knepley 
1979566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
1986913077dSMatthew G. Knepley       /* TODO Create names for components */
1996913077dSMatthew G. Knepley       for (c = 0; c < Nc[f]; ++c, ++l) {
2009566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(disc, &fname));
201c6a7a370SJeremy L Thompson         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
202c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
203c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
2049566063dSJacob Faibussowitsch         PetscCall(PetscStrallocpy(tmpname, &names[l]));
2056913077dSMatthew G. Knepley       }
2066913077dSMatthew G. Knepley     }
2076913077dSMatthew G. Knepley   }
2089566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
2096913077dSMatthew G. Knepley   /* Just add P_1 support for now */
2109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2119566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2129566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
2139566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
2146913077dSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
2156913077dSMatthew G. Knepley     PetscScalar *x, *svals;
2166913077dSMatthew G. Knepley 
2179566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
2186913077dSMatthew G. Knepley     for (i = 0; i < n; ++i) {
2199566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
2206913077dSMatthew G. Knepley       for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
2216913077dSMatthew G. Knepley     }
2229566063dSJacob Faibussowitsch     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
2236913077dSMatthew G. Knepley   }
2249566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
2259566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
2269566063dSJacob Faibussowitsch   for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
2279566063dSJacob Faibussowitsch   PetscCall(PetscFree3(sol, names, vals));
2286913077dSMatthew G. Knepley 
2299566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDraw(lg));
2309566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDestroy(&lg));
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2326913077dSMatthew G. Knepley }
2336913077dSMatthew G. Knepley 
234d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
235d71ae5a4SJacob Faibussowitsch {
2366913077dSMatthew G. Knepley   DM dm;
2376913077dSMatthew G. Knepley 
2386913077dSMatthew G. Knepley   PetscFunctionBegin;
2399566063dSJacob Faibussowitsch   PetscCall(VecGetDM(u, &dm));
2409566063dSJacob Faibussowitsch   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
2413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2426913077dSMatthew G. Knepley }
2436913077dSMatthew G. Knepley 
244d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
245d71ae5a4SJacob Faibussowitsch {
246e412dcbdSMatthew G. Knepley   DM                 dm;
247d1df6f1dSMatthew G. Knepley   PetscSection       s;
248e412dcbdSMatthew G. Knepley   PetscDraw          draw, popup;
249e412dcbdSMatthew G. Knepley   DM                 cdm;
250e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
251e412dcbdSMatthew G. Knepley   Vec                coordinates;
252c9c77995SMatthew G. Knepley   const PetscScalar *array;
253c9c77995SMatthew G. Knepley   PetscReal          lbound[3], ubound[3];
254339e3443SMatthew G. Knepley   PetscReal          vbound[2], time;
2556913077dSMatthew G. Knepley   PetscBool          flg;
256d1df6f1dSMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
257e412dcbdSMatthew G. Knepley   const char        *name;
258339e3443SMatthew G. Knepley   char               title[PETSC_MAX_PATH_LEN];
259e412dcbdSMatthew G. Knepley 
260e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
2619566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2629566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
2639566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
2649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
2659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
2669566063dSJacob Faibussowitsch   PetscCall(DMGetCoarsenLevel(dm, &level));
2679566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
2689566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
2699566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
272e412dcbdSMatthew G. Knepley 
2739566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
2749566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
275e412dcbdSMatthew G. Knepley 
2769566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
277c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
2789566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
279e412dcbdSMatthew G. Knepley 
280d1df6f1dSMatthew G. Knepley   /* Could implement something like DMDASelectFields() */
281d1df6f1dSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
282d1df6f1dSMatthew G. Knepley     DM          fdm = dm;
283d1df6f1dSMatthew G. Knepley     Vec         fv  = v;
284d1df6f1dSMatthew G. Knepley     IS          fis;
285d1df6f1dSMatthew G. Knepley     char        prefix[PETSC_MAX_PATH_LEN];
286d1df6f1dSMatthew G. Knepley     const char *fname;
287d1df6f1dSMatthew G. Knepley 
2889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(s, f, &fname));
290d1df6f1dSMatthew G. Knepley 
2919566063dSJacob Faibussowitsch     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
292ad540459SPierre Jolivet     else prefix[0] = '\0';
293d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
2949566063dSJacob Faibussowitsch       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
2959566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(v, fis, &fv));
2969566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
2979566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
298d1df6f1dSMatthew G. Knepley     }
299d1df6f1dSMatthew G. Knepley     for (comp = 0; comp < Nc; ++comp, ++w) {
300d1df6f1dSMatthew G. Knepley       PetscInt nmax = 2;
301d1df6f1dSMatthew G. Knepley 
3029566063dSJacob Faibussowitsch       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
30363a3b9bcSJacob Faibussowitsch       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
30463a3b9bcSJacob Faibussowitsch       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
3059566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetTitle(draw, title));
306d1df6f1dSMatthew G. Knepley 
307d1df6f1dSMatthew G. Knepley       /* TODO Get max and min only for this component */
3089566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
309339e3443SMatthew G. Knepley       if (!flg) {
3109566063dSJacob Faibussowitsch         PetscCall(VecMin(fv, NULL, &vbound[0]));
3119566063dSJacob Faibussowitsch         PetscCall(VecMax(fv, NULL, &vbound[1]));
312d1df6f1dSMatthew G. Knepley         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
313339e3443SMatthew G. Knepley       }
314c9c77995SMatthew G. Knepley 
3159566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetPopup(draw, &popup));
3169566063dSJacob Faibussowitsch       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
317c9c77995SMatthew G. Knepley       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
3189566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(fv, &array));
319e412dcbdSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
32099a2f7bcSMatthew G. Knepley         PetscScalar       *coords = NULL, *a = NULL;
321c9c77995SMatthew G. Knepley         const PetscScalar *coords_arr;
322c9c77995SMatthew G. Knepley         PetscBool          isDG;
323e56f9228SJed Brown         PetscInt           numCoords, color[4] = {-1, -1, -1, -1};
324e412dcbdSMatthew G. Knepley 
3259566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
326339e3443SMatthew G. Knepley         if (a) {
327d1df6f1dSMatthew G. Knepley           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
328339e3443SMatthew G. Knepley           color[1] = color[2] = color[3] = color[0];
329339e3443SMatthew G. Knepley         } else {
330339e3443SMatthew G. Knepley           PetscScalar *vals = NULL;
331339e3443SMatthew G. Knepley           PetscInt     numVals, va;
332339e3443SMatthew G. Knepley 
3339566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
33463a3b9bcSJacob Faibussowitsch           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);
335d1df6f1dSMatthew G. Knepley           switch (numVals / Nc) {
336d1df6f1dSMatthew G. Knepley           case 3: /* P1 Triangle */
337d1df6f1dSMatthew G. Knepley           case 4: /* P1 Quadrangle */
338d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
339339e3443SMatthew G. Knepley             break;
340d1df6f1dSMatthew G. Knepley           case 6: /* P2 Triangle */
341d1df6f1dSMatthew G. Knepley           case 8: /* P2 Quadrangle */
342d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]);
343d1df6f1dSMatthew G. Knepley             break;
344d71ae5a4SJacob Faibussowitsch           default:
345d71ae5a4SJacob Faibussowitsch             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
346339e3443SMatthew G. Knepley           }
3479566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
348339e3443SMatthew G. Knepley         }
349c9c77995SMatthew G. Knepley         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
350e412dcbdSMatthew G. Knepley         switch (numCoords) {
351e412dcbdSMatthew G. Knepley         case 6:
3529edc3542SMatthew Knepley         case 12: /* Localized triangle */
3539566063dSJacob Faibussowitsch           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]));
354e412dcbdSMatthew G. Knepley           break;
355e412dcbdSMatthew G. Knepley         case 8:
3569edc3542SMatthew Knepley         case 16: /* Localized quadrilateral */
3579566063dSJacob Faibussowitsch           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]));
3589566063dSJacob Faibussowitsch           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]));
359e412dcbdSMatthew G. Knepley           break;
360d71ae5a4SJacob Faibussowitsch         default:
361d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
362e412dcbdSMatthew G. Knepley         }
363c9c77995SMatthew G. Knepley         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
364e412dcbdSMatthew G. Knepley       }
3659566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(fv, &array));
3669566063dSJacob Faibussowitsch       PetscCall(PetscDrawFlush(draw));
3679566063dSJacob Faibussowitsch       PetscCall(PetscDrawPause(draw));
3689566063dSJacob Faibussowitsch       PetscCall(PetscDrawSave(draw));
369d1df6f1dSMatthew G. Knepley     }
370d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
3719566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(v, fis, &fv));
3729566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&fis));
3739566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&fdm));
374d1df6f1dSMatthew G. Knepley     }
375d1df6f1dSMatthew G. Knepley   }
3763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
377e412dcbdSMatthew G. Knepley }
378e412dcbdSMatthew G. Knepley 
379d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
380d71ae5a4SJacob Faibussowitsch {
3816913077dSMatthew G. Knepley   DM        dm;
3826913077dSMatthew G. Knepley   PetscDraw draw;
3836913077dSMatthew G. Knepley   PetscInt  dim;
3846913077dSMatthew G. Knepley   PetscBool isnull;
3856913077dSMatthew G. Knepley 
3866913077dSMatthew G. Knepley   PetscFunctionBegin;
3879566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3889566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
3893ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
3906913077dSMatthew G. Knepley 
3919566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
3929566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
3936913077dSMatthew G. Knepley   switch (dim) {
394d71ae5a4SJacob Faibussowitsch   case 1:
395d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
396d71ae5a4SJacob Faibussowitsch     break;
397d71ae5a4SJacob Faibussowitsch   case 2:
398d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
399d71ae5a4SJacob Faibussowitsch     break;
400d71ae5a4SJacob Faibussowitsch   default:
401d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
4026913077dSMatthew G. Knepley   }
4033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4046913077dSMatthew G. Knepley }
4056913077dSMatthew G. Knepley 
406d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
407d71ae5a4SJacob Faibussowitsch {
408684b87d9SLisandro Dalcin   DM                      dm;
409684b87d9SLisandro Dalcin   Vec                     locv;
410684b87d9SLisandro Dalcin   const char             *name;
411684b87d9SLisandro Dalcin   PetscSection            section;
412684b87d9SLisandro Dalcin   PetscInt                pStart, pEnd;
413e630c359SToby Isaac   PetscInt                numFields;
414684b87d9SLisandro Dalcin   PetscViewerVTKFieldType ft;
415684b87d9SLisandro Dalcin 
416684b87d9SLisandro Dalcin   PetscFunctionBegin;
4179566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
4189566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
4199566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
4209566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)locv, name));
4219566063dSJacob Faibussowitsch   PetscCall(VecCopy(v, locv));
4229566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
4239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
424e630c359SToby Isaac   if (!numFields) {
4259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
4269566063dSJacob Faibussowitsch     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
427e630c359SToby Isaac   } else {
428e630c359SToby Isaac     PetscInt f;
429e630c359SToby Isaac 
430e630c359SToby Isaac     for (f = 0; f < numFields; f++) {
4319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
432e630c359SToby Isaac       if (ft == PETSC_VTK_INVALID) continue;
4339566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)locv));
4349566063dSJacob Faibussowitsch       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
435e630c359SToby Isaac     }
4369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locv));
437e630c359SToby Isaac   }
4383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
439684b87d9SLisandro Dalcin }
440684b87d9SLisandro Dalcin 
441d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
442d71ae5a4SJacob Faibussowitsch {
443552f7358SJed Brown   DM        dm;
4445f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;
445552f7358SJed Brown 
446552f7358SJed Brown   PetscFunctionBegin;
4479566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
44828b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
4499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
4509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
4529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
4535f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
4545f34f2dcSJed Brown   if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
455684b87d9SLisandro Dalcin     PetscInt    i, numFields;
456684b87d9SLisandro Dalcin     PetscObject fe;
457ef31f671SMatthew G. Knepley     PetscBool   fem  = PETSC_FALSE;
458684b87d9SLisandro Dalcin     Vec         locv = v;
459684b87d9SLisandro Dalcin     const char *name;
460684b87d9SLisandro Dalcin     PetscInt    step;
461684b87d9SLisandro Dalcin     PetscReal   time;
462ef31f671SMatthew G. Knepley 
4639566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &numFields));
464684b87d9SLisandro Dalcin     for (i = 0; i < numFields; i++) {
4659566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, i, NULL, &fe));
4669371c9d4SSatish Balay       if (fe->classid == PETSCFE_CLASSID) {
4679371c9d4SSatish Balay         fem = PETSC_TRUE;
4689371c9d4SSatish Balay         break;
4699371c9d4SSatish Balay       }
470ef31f671SMatthew G. Knepley     }
471684b87d9SLisandro Dalcin     if (fem) {
472798534f6SMatthew G. Knepley       PetscObject isZero;
473798534f6SMatthew G. Knepley 
4749566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &locv));
4759566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)v, &name));
4769566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)locv, name));
4779566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
4789566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
4799566063dSJacob Faibussowitsch       PetscCall(VecCopy(v, locv));
4809566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
4819566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
482ef31f671SMatthew G. Knepley     }
483552f7358SJed Brown     if (isvtk) {
4849566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
485b136c2c9SMatthew G. Knepley     } else if (ishdf5) {
486b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
4879566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
488b136c2c9SMatthew G. Knepley #else
489b136c2c9SMatthew G. Knepley       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
490b136c2c9SMatthew G. Knepley #endif
491f13a32a3SMatthew G. Knepley     } else if (isdraw) {
4929566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
493684b87d9SLisandro Dalcin     } else if (isglvis) {
4949566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
4959566063dSJacob Faibussowitsch       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
4969566063dSJacob Faibussowitsch       PetscCall(VecView_GLVis(locv, viewer));
4975f34f2dcSJed Brown     } else if (iscgns) {
4985f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
4995f34f2dcSJed Brown       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
5005f34f2dcSJed Brown #else
5015f34f2dcSJed Brown       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
5025f34f2dcSJed Brown #endif
503684b87d9SLisandro Dalcin     }
504798534f6SMatthew G. Knepley     if (fem) {
5059566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
5069566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &locv));
507798534f6SMatthew G. Knepley     }
508552f7358SJed Brown   } else {
509684b87d9SLisandro Dalcin     PetscBool isseq;
510684b87d9SLisandro Dalcin 
5119566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
5129566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
5139566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
514552f7358SJed Brown   }
5153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
516552f7358SJed Brown }
517552f7358SJed Brown 
518d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
519d71ae5a4SJacob Faibussowitsch {
520552f7358SJed Brown   DM        dm;
5215f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;
522552f7358SJed Brown 
523552f7358SJed Brown   PetscFunctionBegin;
5249566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
52528b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5269566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
5279566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
5305f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
5325f34f2dcSJed Brown   if (isvtk || isdraw || isglvis || iscgns) {
533552f7358SJed Brown     Vec         locv;
534798534f6SMatthew G. Knepley     PetscObject isZero;
535552f7358SJed Brown     const char *name;
536552f7358SJed Brown 
5379566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &locv));
5389566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
5399566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)locv, name));
5409566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
5419566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
5429566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
5439566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
5449566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_Local(locv, viewer));
5459566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
5469566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &locv));
547b136c2c9SMatthew G. Knepley   } else if (ishdf5) {
548b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
5499566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
550b136c2c9SMatthew G. Knepley #else
551b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
552b136c2c9SMatthew G. Knepley #endif
5536823f3c5SBlaise Bourdin   } else if (isexodusii) {
5546823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
5559566063dSJacob Faibussowitsch     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
5566823f3c5SBlaise Bourdin #else
5576823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
5586823f3c5SBlaise Bourdin #endif
559552f7358SJed Brown   } else {
560684b87d9SLisandro Dalcin     PetscBool isseq;
561684b87d9SLisandro Dalcin 
5629566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
5639566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
5649566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
565552f7358SJed Brown   }
5663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
567552f7358SJed Brown }
568552f7358SJed Brown 
569d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
570d71ae5a4SJacob Faibussowitsch {
571d930f514SMatthew G. Knepley   DM                dm;
572d930f514SMatthew G. Knepley   MPI_Comm          comm;
573d930f514SMatthew G. Knepley   PetscViewerFormat format;
574d930f514SMatthew G. Knepley   Vec               v;
575d930f514SMatthew G. Knepley   PetscBool         isvtk, ishdf5;
576d930f514SMatthew G. Knepley 
577d930f514SMatthew G. Knepley   PetscFunctionBegin;
5789566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
5799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
58028b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5819566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
5829566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5839566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
584d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
585a8ad634aSStefano Zampini     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
586a8ad634aSStefano Zampini     /* this need a better fix */
587a8ad634aSStefano Zampini     if (dm->useNatural) {
588a8ad634aSStefano Zampini       if (dm->sfNatural) {
589d930f514SMatthew G. Knepley         const char *vecname;
590d930f514SMatthew G. Knepley         PetscInt    n, nroots;
591d930f514SMatthew G. Knepley 
5929566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(originalv, &n));
5939566063dSJacob Faibussowitsch         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
594d930f514SMatthew G. Knepley         if (n == nroots) {
595f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
5969566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
5979566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
5989566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
5999566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
600d930f514SMatthew G. Knepley         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
601d930f514SMatthew G. Knepley       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
602a8ad634aSStefano Zampini     } else v = originalv;
603a8ad634aSStefano Zampini   } else v = originalv;
604a8ad634aSStefano Zampini 
605d930f514SMatthew G. Knepley   if (ishdf5) {
606d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6079566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
608d930f514SMatthew G. Knepley #else
609d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
610d930f514SMatthew G. Knepley #endif
611d930f514SMatthew G. Knepley   } else if (isvtk) {
612d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
613d930f514SMatthew G. Knepley   } else {
614d930f514SMatthew G. Knepley     PetscBool isseq;
615d930f514SMatthew G. Knepley 
6169566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
6179566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
6189566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
619d930f514SMatthew G. Knepley   }
620f16a8b29SMatthew G. Knepley   if (v != originalv) PetscCall(VecDestroy(&v));
6213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
622d930f514SMatthew G. Knepley }
623d930f514SMatthew G. Knepley 
624d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
625d71ae5a4SJacob Faibussowitsch {
6262c40f234SMatthew G. Knepley   DM        dm;
6272c40f234SMatthew G. Knepley   PetscBool ishdf5;
6282c40f234SMatthew G. Knepley 
6292c40f234SMatthew G. Knepley   PetscFunctionBegin;
6309566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
63128b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6332c40f234SMatthew G. Knepley   if (ishdf5) {
6342c40f234SMatthew G. Knepley     DM          dmBC;
6352c40f234SMatthew G. Knepley     Vec         gv;
6362c40f234SMatthew G. Knepley     const char *name;
6372c40f234SMatthew G. Knepley 
6389566063dSJacob Faibussowitsch     PetscCall(DMGetOutputDM(dm, &dmBC));
6399566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmBC, &gv));
6409566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
6419566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)gv, name));
6429566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(gv, viewer));
6439566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
6449566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
6459566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
6461baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
6473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6482c40f234SMatthew G. Knepley }
6492c40f234SMatthew G. Knepley 
650d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
651d71ae5a4SJacob Faibussowitsch {
6522c40f234SMatthew G. Knepley   DM        dm;
6536823f3c5SBlaise Bourdin   PetscBool ishdf5, isexodusii;
6542c40f234SMatthew G. Knepley 
6552c40f234SMatthew G. Knepley   PetscFunctionBegin;
6569566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
65728b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6599566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
6602c40f234SMatthew G. Knepley   if (ishdf5) {
661878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6629566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
663b136c2c9SMatthew G. Knepley #else
664b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
665878b459fSMatthew G. Knepley #endif
6666823f3c5SBlaise Bourdin   } else if (isexodusii) {
6676823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
6689566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
6696823f3c5SBlaise Bourdin #else
6706823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
6716823f3c5SBlaise Bourdin #endif
6721baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
6733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
674552f7358SJed Brown }
675552f7358SJed Brown 
676d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
677d71ae5a4SJacob Faibussowitsch {
678d930f514SMatthew G. Knepley   DM                dm;
679d930f514SMatthew G. Knepley   PetscViewerFormat format;
680d930f514SMatthew G. Knepley   PetscBool         ishdf5;
681d930f514SMatthew G. Knepley 
682d930f514SMatthew G. Knepley   PetscFunctionBegin;
6839566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
68428b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6859566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
6869566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
687d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
688a8ad634aSStefano Zampini     if (dm->useNatural) {
689d930f514SMatthew G. Knepley       if (dm->sfNatural) {
690d930f514SMatthew G. Knepley         if (ishdf5) {
691d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
692d930f514SMatthew G. Knepley           Vec         v;
693d930f514SMatthew G. Knepley           const char *vecname;
694d930f514SMatthew G. Knepley 
695f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
6969566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
6979566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
6989566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
6999566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
7009566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
701f16a8b29SMatthew G. Knepley           PetscCall(VecDestroy(&v));
702d930f514SMatthew G. Knepley #else
703d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
704d930f514SMatthew G. Knepley #endif
705d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
706d930f514SMatthew G. Knepley       }
7071baa6e33SBarry Smith     } else PetscCall(VecLoad_Default(originalv, viewer));
708d930f514SMatthew G. Knepley   }
7093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
710d930f514SMatthew G. Knepley }
711d930f514SMatthew G. Knepley 
712d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
713d71ae5a4SJacob Faibussowitsch {
714731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
715731e8ddeSMatthew G. Knepley   Vec                coordinates;
716ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
717731e8ddeSMatthew G. Knepley   const char        *name[4];
718731e8ddeSMatthew G. Knepley   const PetscScalar *a;
719731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
720731e8ddeSMatthew G. Knepley 
721731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
7229566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
7239566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
7249566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
7269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
7279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
7299566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
730731e8ddeSMatthew G. Knepley   name[0]       = "vertex";
731731e8ddeSMatthew G. Knepley   name[1]       = "edge";
732731e8ddeSMatthew G. Knepley   name[dim - 1] = "face";
733731e8ddeSMatthew G. Knepley   name[dim]     = "cell";
734731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
735731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
736ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
737731e8ddeSMatthew G. Knepley 
7389566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
73963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
7409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7419566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
742731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
743731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
744731e8ddeSMatthew G. Knepley 
745731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
7469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
747731e8ddeSMatthew G. Knepley       if (!dof) continue;
7489566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
7499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
75063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
751731e8ddeSMatthew G. Knepley       for (p = 0; p < dof / dim; ++p) {
7529566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
753731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
7549566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
7559566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
756731e8ddeSMatthew G. Knepley         }
7579566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
758731e8ddeSMatthew G. Knepley       }
7599566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
760731e8ddeSMatthew G. Knepley     }
7619566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7629566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
763731e8ddeSMatthew G. Knepley   }
7649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
7653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
766731e8ddeSMatthew G. Knepley }
767731e8ddeSMatthew G. Knepley 
7689371c9d4SSatish Balay typedef enum {
7699371c9d4SSatish Balay   CS_CARTESIAN,
7709371c9d4SSatish Balay   CS_POLAR,
7719371c9d4SSatish Balay   CS_CYLINDRICAL,
7729371c9d4SSatish Balay   CS_SPHERICAL
7739371c9d4SSatish Balay } CoordSystem;
77419ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
77519ad8254SMatthew G. Knepley 
776d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
777d71ae5a4SJacob Faibussowitsch {
77819ad8254SMatthew G. Knepley   PetscInt i;
77919ad8254SMatthew G. Knepley 
78019ad8254SMatthew G. Knepley   PetscFunctionBegin;
78119ad8254SMatthew G. Knepley   if (dim > 3) {
7829566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
78319ad8254SMatthew G. Knepley   } else {
784bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
78519ad8254SMatthew G. Knepley 
78619ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
78719ad8254SMatthew G. Knepley     switch (cs) {
7889371c9d4SSatish Balay     case CS_CARTESIAN:
7899371c9d4SSatish Balay       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
7909371c9d4SSatish Balay       break;
79119ad8254SMatthew G. Knepley     case CS_POLAR:
79263a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
79319ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
79419ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
79519ad8254SMatthew G. Knepley       break;
79619ad8254SMatthew G. Knepley     case CS_CYLINDRICAL:
79763a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
79819ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
79919ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
80019ad8254SMatthew G. Knepley       trcoords[2] = coords[2];
80119ad8254SMatthew G. Knepley       break;
80219ad8254SMatthew G. Knepley     case CS_SPHERICAL:
80363a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
80419ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
80519ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
80619ad8254SMatthew G. Knepley       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
80719ad8254SMatthew G. Knepley       break;
80819ad8254SMatthew G. Knepley     }
8099566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
81019ad8254SMatthew G. Knepley   }
8113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81219ad8254SMatthew G. Knepley }
81319ad8254SMatthew G. Knepley 
814d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
815d71ae5a4SJacob Faibussowitsch {
816552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex *)dm->data;
8176858538eSMatthew G. Knepley   DM                cdm, cdmCell;
8186858538eSMatthew G. Knepley   PetscSection      coordSection, coordSectionCell;
8196858538eSMatthew G. Knepley   Vec               coordinates, coordinatesCell;
820552f7358SJed Brown   PetscViewerFormat format;
821552f7358SJed Brown 
822552f7358SJed Brown   PetscFunctionBegin;
8239566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
824552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
825552f7358SJed Brown     const char *name;
826f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
8279318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
828552f7358SJed Brown     PetscMPIInt rank, size;
829552f7358SJed Brown 
8309f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
8319f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
8329f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8339f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
8349f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
8359f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
8369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
8379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
8389566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
8399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
8419566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
8429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
84363a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
84463a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
84563a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
84663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
8479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
84863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
849552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
850552f7358SJed Brown       PetscInt dof, off, s;
851552f7358SJed Brown 
8529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
85448a46eb9SPierre Jolivet       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
855552f7358SJed Brown     }
8569566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
85763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
85863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
859552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
860552f7358SJed Brown       PetscInt dof, off, c;
861552f7358SJed Brown 
8629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
8639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
86448a46eb9SPierre Jolivet       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]));
865552f7358SJed Brown     }
8669566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
8679566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8683d2e540fSStefano Zampini     if (coordSection && coordinates) {
86919ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
8706858538eSMatthew G. Knepley       const PetscScalar *array, *arrayCell = NULL;
8716858538eSMatthew G. Knepley       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
87219ad8254SMatthew G. Knepley       PetscMPIInt        rank;
87319ad8254SMatthew G. Knepley       const char        *name;
87419ad8254SMatthew G. Knepley 
8759566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
8769566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
8779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
87863a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
8799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
8806858538eSMatthew G. Knepley       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
8816858538eSMatthew G. Knepley       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
8826858538eSMatthew G. Knepley       pStart = PetscMin(pvStart, pcStart);
8836858538eSMatthew G. Knepley       pEnd   = PetscMax(pvEnd, pcEnd);
8849566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
88563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
88663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
8879566063dSJacob Faibussowitsch       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
88819ad8254SMatthew G. Knepley 
8899566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordinates, &array));
8906858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
8919566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
89319ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
89419ad8254SMatthew G. Knepley         PetscInt dof, off;
89519ad8254SMatthew G. Knepley 
8966858538eSMatthew G. Knepley         if (p >= pvStart && p < pvEnd) {
8979566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
8989566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
8996858538eSMatthew G. Knepley           if (dof) {
90063a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
9019566063dSJacob Faibussowitsch             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
9029566063dSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
90319ad8254SMatthew G. Knepley           }
9046858538eSMatthew G. Knepley         }
9056858538eSMatthew G. Knepley         if (cdmCell && p >= pcStart && p < pcEnd) {
9066858538eSMatthew G. Knepley           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
9076858538eSMatthew G. Knepley           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
9086858538eSMatthew G. Knepley           if (dof) {
9096858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
9106858538eSMatthew G. Knepley             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
9116858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
9126858538eSMatthew G. Knepley           }
9136858538eSMatthew G. Knepley         }
9146858538eSMatthew G. Knepley       }
9159566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
9169566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
9179566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
9186858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
9193d2e540fSStefano Zampini     }
9209566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
9219566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
9229318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
9239318fe57SMatthew G. Knepley       DMLabel     label;
9249318fe57SMatthew G. Knepley       PetscBool   isdepth;
9259318fe57SMatthew G. Knepley       const char *name;
9269318fe57SMatthew G. Knepley 
9279566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
9289566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
9299318fe57SMatthew G. Knepley       if (isdepth) continue;
9309566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
9319566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
9329318fe57SMatthew G. Knepley     }
933552f7358SJed Brown     if (size > 1) {
934552f7358SJed Brown       PetscSF sf;
935552f7358SJed Brown 
9369566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
9379566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
938552f7358SJed Brown     }
9394e2e9504SJed Brown     if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer));
9409566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
941552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
9420588280cSMatthew G. Knepley     const char  *name, *color;
9430588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
9440588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
945fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
946552f7358SJed Brown     PetscReal    scale      = 2.0;
94778081901SStefano Zampini     PetscReal    tikzscale  = 1.0;
948b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
9490588280cSMatthew G. Knepley     double       tcoords[3];
950552f7358SJed Brown     PetscScalar *coords;
951b7f6ffafSMatthew G. Knepley     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
952552f7358SJed Brown     PetscMPIInt  rank, size;
9530588280cSMatthew G. Knepley     char       **names, **colors, **lcolors;
954b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
955fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
956fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
957552f7358SJed Brown 
9589f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
9599f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
9609f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
9619f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
9629f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
9639f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
9649566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
9669566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
9670588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
9680588280cSMatthew G. Knepley     numColors  = 10;
9690588280cSMatthew G. Knepley     numLColors = 10;
9709566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
9719566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
9729566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
9739566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
974b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
975b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
976b7f6ffafSMatthew G. Knepley     n = 4;
9779566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
9781dca8a05SBarry Smith     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
9799566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
9801dca8a05SBarry Smith     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
9819566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
9820588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
9839566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
9840588280cSMatthew G. Knepley     if (!useColors) {
9850588280cSMatthew G. Knepley       numColors = 3;
9869566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
9870588280cSMatthew G. Knepley     }
9889566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
9890588280cSMatthew G. Knepley     if (!useColors) {
9900588280cSMatthew G. Knepley       numLColors = 4;
9919566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
9920588280cSMatthew G. Knepley     }
9939566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
994b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
9959566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
9961dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
997202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
9989566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
999fe1cc32dSStefano Zampini 
1000fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
10019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
10029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
10039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
10049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1005fe1cc32dSStefano Zampini     if (lflg) {
1006fe1cc32dSStefano Zampini       DMLabel lbl;
1007fe1cc32dSStefano Zampini 
10089566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
1009fe1cc32dSStefano Zampini       if (lbl) {
1010fe1cc32dSStefano Zampini         PetscInt val, defval;
1011fe1cc32dSStefano Zampini 
10129566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
10139566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1014fe1cc32dSStefano Zampini         for (c = pStart; c < pEnd; c++) {
1015fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
1016fe1cc32dSStefano Zampini           PetscInt  closureSize;
1017fe1cc32dSStefano Zampini 
10189566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
1019fe1cc32dSStefano Zampini           if (val == defval) continue;
1020fe1cc32dSStefano Zampini 
10219566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
102248a46eb9SPierre Jolivet           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
10239566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1024fe1cc32dSStefano Zampini         }
1025fe1cc32dSStefano Zampini       }
1026fe1cc32dSStefano Zampini     }
1027fe1cc32dSStefano Zampini 
10289566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
10299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
10309566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
10319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
10320588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
1033552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
1034552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
1035552f7358SJed Brown \\usetikzlibrary{arrows}\n\
10365f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
10370588280cSMatthew G. Knepley     if (size > 1) {
10389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1039770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
104063a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
104163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1042770b213bSMatthew G Knepley       }
10439566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
10440588280cSMatthew G. Knepley     }
1045b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1046b7f6ffafSMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart));
1047b7f6ffafSMatthew G. Knepley 
104863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
104963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
105063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
10519566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
105263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
105363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
10549566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
105563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
105663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
105763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
105863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
10599566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1060b7f6ffafSMatthew G. Knepley     }
10619566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1062fe1cc32dSStefano Zampini 
1063552f7358SJed Brown     /* Plot vertices */
10649566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
10659566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1066552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1067552f7358SJed Brown       PetscInt  off, dof, d;
10680588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1069552f7358SJed Brown 
1070fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
10719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
10729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
10739566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
107463a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
10750588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
10760588280cSMatthew G. Knepley         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1077c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
10780588280cSMatthew G. Knepley       }
10790588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
10809371c9d4SSatish Balay       if (dim == 3) {
10819371c9d4SSatish Balay         PetscReal tmp = tcoords[1];
10829371c9d4SSatish Balay         tcoords[1]    = tcoords[2];
10839371c9d4SSatish Balay         tcoords[2]    = -tmp;
10849371c9d4SSatish Balay       }
1085552f7358SJed Brown       for (d = 0; d < dof; ++d) {
10869566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
10879566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1088552f7358SJed Brown       }
1089b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0 % numColors];
1090b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
10910588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
10920588280cSMatthew G. Knepley         PetscInt val;
10939566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
10949371c9d4SSatish Balay         if (val >= 0) {
10959371c9d4SSatish Balay           color     = lcolors[l % numLColors];
10969371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
10979371c9d4SSatish Balay           break;
10989371c9d4SSatish Balay         }
10990588280cSMatthew G. Knepley       }
1100b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
110163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1102b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
110363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
11041baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1105552f7358SJed Brown     }
11069566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
11079566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1108b7f6ffafSMatthew G. Knepley     /* Plot edges */
1109b7f6ffafSMatthew G. Knepley     if (plotEdges) {
11109566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
11119566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1112b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1113b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1114b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1115b7f6ffafSMatthew G. Knepley 
1116b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
11179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
111863a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
11199566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
11209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
11219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
11229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
11239566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1124b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1125b7f6ffafSMatthew G. Knepley           tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1126b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1127b7f6ffafSMatthew G. Knepley         }
1128b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
11299371c9d4SSatish Balay         if (dim == 3) {
11309371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
11319371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
11329371c9d4SSatish Balay           tcoords[2]    = -tmp;
11339371c9d4SSatish Balay         }
1134b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
11359566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
11369566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1137b7f6ffafSMatthew G. Knepley         }
1138b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1 % numColors];
1139b7f6ffafSMatthew G. Knepley         else color = colors[rank % numColors];
1140b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1141b7f6ffafSMatthew G. Knepley           PetscInt val;
11429566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], v, &val));
11439371c9d4SSatish Balay           if (val >= 0) {
11449371c9d4SSatish Balay             color = lcolors[l % numLColors];
11459371c9d4SSatish Balay             break;
11469371c9d4SSatish Balay           }
1147b7f6ffafSMatthew G. Knepley         }
114863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1149b7f6ffafSMatthew G. Knepley       }
11509566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
11519566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
11529566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1153b7f6ffafSMatthew G. Knepley     }
1154846a3e8bSMatthew G. Knepley     /* Plot cells */
1155b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1156846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1157846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1158846a3e8bSMatthew G. Knepley 
1159fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1160846a3e8bSMatthew G. Knepley         color = colors[rank % numColors];
1161846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1162846a3e8bSMatthew G. Knepley           PetscInt val;
11639566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
11649371c9d4SSatish Balay           if (val >= 0) {
11659371c9d4SSatish Balay             color = lcolors[l % numLColors];
11669371c9d4SSatish Balay             break;
11679371c9d4SSatish Balay           }
1168846a3e8bSMatthew G. Knepley         }
11699566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
117063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1171846a3e8bSMatthew G. Knepley       }
1172846a3e8bSMatthew G. Knepley     } else {
1173b7f6ffafSMatthew G. Knepley       DMPolytopeType ct;
1174846a3e8bSMatthew G. Knepley 
1175b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1176b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1177fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
11789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
11799371c9d4SSatish Balay         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1180b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1181b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1182b7f6ffafSMatthew G. Knepley 
11839566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
11849566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1185b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1186b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1187b7f6ffafSMatthew G. Knepley 
11889566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
118963a3b9bcSJacob Faibussowitsch             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));
1190b7f6ffafSMatthew G. Knepley           }
1191b7f6ffafSMatthew G. Knepley         } else {
1192b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1193b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1194b7f6ffafSMatthew G. Knepley 
11959566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1196846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize * 2; p += 2) {
1197846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1198846a3e8bSMatthew G. Knepley 
1199b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1200846a3e8bSMatthew G. Knepley           }
12019566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1202b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1203b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v % Nv];
1204b7f6ffafSMatthew G. Knepley 
1205b7f6ffafSMatthew G. Knepley             if (v > 0) {
1206b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1207b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1208b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1209b7f6ffafSMatthew G. Knepley 
12109371c9d4SSatish Balay                 endpoints[0] = closure[v - 1];
12119371c9d4SSatish Balay                 endpoints[1] = vertex;
12129566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
121363a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
121463a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
12159566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
12161baa6e33SBarry Smith               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1217b7f6ffafSMatthew G. Knepley             }
121863a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1219b7f6ffafSMatthew G. Knepley           }
12209566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
12219566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1222846a3e8bSMatthew G. Knepley         }
1223846a3e8bSMatthew G. Knepley       }
1224b7f6ffafSMatthew G. Knepley     }
1225846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1226846a3e8bSMatthew G. Knepley       double             ccoords[3] = {0.0, 0.0, 0.0};
1227846a3e8bSMatthew G. Knepley       PetscBool          isLabeled  = PETSC_FALSE;
1228c713ec31SMatthew G. Knepley       PetscScalar       *cellCoords = NULL;
1229c713ec31SMatthew G. Knepley       const PetscScalar *array;
1230c713ec31SMatthew G. Knepley       PetscInt           numCoords, cdim, d;
1231c713ec31SMatthew G. Knepley       PetscBool          isDG;
1232846a3e8bSMatthew G. Knepley 
1233fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1234c713ec31SMatthew G. Knepley       PetscCall(DMGetCoordinateDim(dm, &cdim));
1235c713ec31SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1236c713ec31SMatthew G. Knepley       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
12379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1238c713ec31SMatthew G. Knepley       for (p = 0; p < numCoords / cdim; ++p) {
1239c713ec31SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
1240c713ec31SMatthew G. Knepley           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1241846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1242846a3e8bSMatthew G. Knepley         }
1243846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
12449371c9d4SSatish Balay         if (cdim == 3) {
12459371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
12469371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
12479371c9d4SSatish Balay           tcoords[2]    = -tmp;
12489371c9d4SSatish Balay         }
1249ad540459SPierre Jolivet         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1250846a3e8bSMatthew G. Knepley       }
1251ad540459SPierre Jolivet       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1252c713ec31SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1253c713ec31SMatthew G. Knepley       for (d = 0; d < cdim; ++d) {
12549566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
12559566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1256846a3e8bSMatthew G. Knepley       }
1257b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth % numColors];
1258b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
1259846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1260846a3e8bSMatthew G. Knepley         PetscInt val;
12619566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
12629371c9d4SSatish Balay         if (val >= 0) {
12639371c9d4SSatish Balay           color     = lcolors[l % numLColors];
12649371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
12659371c9d4SSatish Balay           break;
12669371c9d4SSatish Balay         }
1267846a3e8bSMatthew G. Knepley       }
1268b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
126963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1270b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
127163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
12721baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1273846a3e8bSMatthew G. Knepley     }
1274b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1275b7f6ffafSMatthew G. Knepley       color = colors[depth % numColors];
12769566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
12779566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
12789566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12799566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
12809566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1281552f7358SJed Brown 
1282b7f6ffafSMatthew G. Knepley       color = colors[1 % numColors];
12839566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
12849566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
12859566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
12879566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1288b7f6ffafSMatthew G. Knepley 
1289b7f6ffafSMatthew G. Knepley       color = colors[0 % numColors];
12909566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
12919566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
12929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12939566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
12949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1295b7f6ffafSMatthew G. Knepley 
1296b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1297b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1298b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1299b7f6ffafSMatthew G. Knepley 
13009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
13019566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
130248a46eb9SPierre Jolivet         for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
13030588280cSMatthew G. Knepley       }
13040588280cSMatthew G. Knepley     }
13059566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
13069566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
13079566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
130863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
13099566063dSJacob Faibussowitsch     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
13109566063dSJacob Faibussowitsch     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
13119566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
13129566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
13139566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
13140f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
13150f7d6e4aSStefano Zampini     Vec                    cown, acown;
13160f7d6e4aSStefano Zampini     VecScatter             sct;
13170f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
13180f7d6e4aSStefano Zampini     IS                     gid, acis;
13190f7d6e4aSStefano Zampini     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
13200f7d6e4aSStefano Zampini     MPI_Group              ggroup, ngroup;
13210f7d6e4aSStefano Zampini     PetscScalar           *array, nid;
13220f7d6e4aSStefano Zampini     const PetscInt        *idxs;
13230f7d6e4aSStefano Zampini     PetscInt              *idxs2, *start, *adjacency, *work;
13240f7d6e4aSStefano Zampini     PetscInt64             lm[3], gm[3];
13250f7d6e4aSStefano Zampini     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
13260f7d6e4aSStefano Zampini     PetscMPIInt            d1, d2, rank;
13270f7d6e4aSStefano Zampini 
13289566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
13299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1330b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
13319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
13320f7d6e4aSStefano Zampini #endif
13330f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
13349566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
13359566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
13360f7d6e4aSStefano Zampini       d1 = 0;
13379566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
13380f7d6e4aSStefano Zampini       nid = d2;
13399566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
13409566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
13419566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
13420f7d6e4aSStefano Zampini     } else nid = 0.0;
13430f7d6e4aSStefano Zampini 
13440f7d6e4aSStefano Zampini     /* Get connectivity */
13459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
13469566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
13470f7d6e4aSStefano Zampini 
13480f7d6e4aSStefano Zampini     /* filter overlapped local cells */
13499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
13509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid, &idxs));
13519566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid, &cum));
13529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &idxs2));
13530f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
13540f7d6e4aSStefano Zampini       if (idxs[c - cStart] < 0) continue;
13550f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c - cStart];
13560f7d6e4aSStefano Zampini     }
13579566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid, &idxs));
135863a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
13599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13609566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
13610f7d6e4aSStefano Zampini 
13620f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
13639566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
13649566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
13659566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
13669566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown, &array));
13670f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
13689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown, &array));
13699566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
13709566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
13719566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
13729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
13739566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
13749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
13750f7d6e4aSStefano Zampini 
13760f7d6e4aSStefano Zampini     /* compute edgeCut */
13770f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
13789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &work));
13799566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
13809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
13819566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13829566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown, &array));
13830f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
13840f7d6e4aSStefano Zampini       PetscInt totl;
13850f7d6e4aSStefano Zampini 
13860f7d6e4aSStefano Zampini       totl = start[c + 1] - start[c];
13879566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
13880f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
13890f7d6e4aSStefano Zampini         if (work[i] < 0) {
13900f7d6e4aSStefano Zampini           ect += 1;
13910f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
13920f7d6e4aSStefano Zampini         }
13930f7d6e4aSStefano Zampini       }
13940f7d6e4aSStefano Zampini     }
13959566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
13969566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown, &array));
13970f7d6e4aSStefano Zampini     lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
13980f7d6e4aSStefano Zampini     lm[1] = -numVertices;
13991c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
140063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0]));
14010f7d6e4aSStefano Zampini     lm[0] = ect;                     /* edgeCut */
14020f7d6e4aSStefano Zampini     lm[1] = ectn;                    /* node-aware edgeCut */
14030f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
14041c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
140563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1406b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
140763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.));
14080f7d6e4aSStefano Zampini #else
140963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
14100f7d6e4aSStefano Zampini #endif
14119566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
14129566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
14139566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
14149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1415552f7358SJed Brown   } else {
1416412e9a14SMatthew G. Knepley     const char    *name;
1417d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1418412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1419d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1420ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
14219318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1422412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1423412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1424552f7358SJed Brown 
14259566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
14269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
14279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
14289566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
14299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
14309566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
143163a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
143263a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
143363a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
14349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
14351c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
14362827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1437d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
14389566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
14399566063dSJacob Faibussowitsch     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1440412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1441412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1442412e9a14SMatthew G. Knepley 
14439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
14449566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1445412e9a14SMatthew G. Knepley       ict = ct0;
14469566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1447412e9a14SMatthew G. Knepley       ct0 = (DMPolytopeType)ict;
1448412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1449412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1450412e9a14SMatthew G. Knepley 
14519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1452412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1453412e9a14SMatthew G. Knepley         else ++Nc[1];
1454412e9a14SMatthew G. Knepley       }
1455ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
14569566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
14579566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
14589566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
145963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1460834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1461dd400576SPatrick Sanan           if (rank == 0) {
146263a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
146363a3b9bcSJacob Faibussowitsch             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
146463a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1465834065abSMatthew G. Knepley           }
1466cbb7f117SMark Adams         }
1467ca7bf7eeSMatthew G. Knepley       } else {
1468ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1469ca7bf7eeSMatthew G. Knepley 
14709371c9d4SSatish Balay         locMinMax[0] = Nc[0] + Nc[1];
14719371c9d4SSatish Balay         locMinMax[1] = Nc[0] + Nc[1];
14729566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
14739371c9d4SSatish Balay         locMinMax[0] = Nc[1];
14749371c9d4SSatish Balay         locMinMax[1] = Nc[1];
14759566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1476ca7bf7eeSMatthew G. Knepley         if (d == depth) {
14779371c9d4SSatish Balay           locMinMax[0] = gcNum;
14789371c9d4SSatish Balay           locMinMax[1] = gcNum;
14799566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1480ca7bf7eeSMatthew G. Knepley         }
148163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
14829566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
14839566063dSJacob Faibussowitsch         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
14849566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1485ca7bf7eeSMatthew G. Knepley       }
14869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1487552f7358SJed Brown     }
14889566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
14899318fe57SMatthew G. Knepley     {
14909318fe57SMatthew G. Knepley       const PetscReal *maxCell;
14919318fe57SMatthew G. Knepley       const PetscReal *L;
14926858538eSMatthew G. Knepley       PetscBool        localized;
14939318fe57SMatthew G. Knepley 
14944fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
14959566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
14966858538eSMatthew G. Knepley       if (L || localized) {
14976858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
14989566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
14996858538eSMatthew G. Knepley         if (L) {
15006858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
15019318fe57SMatthew G. Knepley           for (d = 0; d < dim; ++d) {
15026858538eSMatthew G. Knepley             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
15036858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
15049318fe57SMatthew G. Knepley           }
15056858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
15066858538eSMatthew G. Knepley         }
15076858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
15089566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
15099318fe57SMatthew G. Knepley       }
15109318fe57SMatthew G. Knepley     }
15119566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
15129566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1513a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1514a57dd577SMatthew G Knepley       DMLabel         label;
1515a57dd577SMatthew G Knepley       const char     *name;
1516a57dd577SMatthew G Knepley       IS              valueIS;
1517a57dd577SMatthew G Knepley       const PetscInt *values;
1518a57dd577SMatthew G Knepley       PetscInt        numValues, v;
1519a57dd577SMatthew G Knepley 
15209566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
15219566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
15229566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
152363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
15249566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValueIS(label, &valueIS));
15259566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(valueIS, &values));
15269566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1527a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1528a57dd577SMatthew G Knepley         PetscInt size;
1529a57dd577SMatthew G Knepley 
15309566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
15319566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
153263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1533a57dd577SMatthew G Knepley       }
15349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
15359566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
15369566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(valueIS, &values));
15379566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&valueIS));
1538a57dd577SMatthew G Knepley     }
1539c1cad2e7SMatthew G. Knepley     {
1540c1cad2e7SMatthew G. Knepley       char    **labelNames;
1541c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1542c1cad2e7SMatthew G. Knepley       PetscBool flg;
1543c1cad2e7SMatthew G. Knepley 
15449566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
15459566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1546c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1547c1cad2e7SMatthew G. Knepley         DMLabel label;
1548c1cad2e7SMatthew G. Knepley 
15499566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1550c1cad2e7SMatthew G. Knepley         if (flg) {
15519566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
15529566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1553c1cad2e7SMatthew G. Knepley         }
15549566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1555c1cad2e7SMatthew G. Knepley       }
15569566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1557c1cad2e7SMatthew G. Knepley     }
155834aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
155934aa8a36SMatthew G. Knepley     if (dm->Nf) {
156034aa8a36SMatthew G. Knepley       PetscInt f;
156134aa8a36SMatthew G. Knepley 
156234aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
156334aa8a36SMatthew G. Knepley         const char *name;
156434aa8a36SMatthew G. Knepley 
15659566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
15669566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
15679566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
15689566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
156934aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
15709566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
15719566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
157234aa8a36SMatthew G. Knepley         } else {
15739566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
15749566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
157534aa8a36SMatthew G. Knepley         }
15769566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
157734aa8a36SMatthew G. Knepley       }
157834aa8a36SMatthew G. Knepley     }
15799566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
15808e7ff633SMatthew G. Knepley     if (cdm) {
15819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
15829f4ada15SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
15839566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
15849566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
15858e7ff633SMatthew G. Knepley     }
1586552f7358SJed Brown   }
15873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1588552f7358SJed Brown }
1589552f7358SJed Brown 
1590d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1591d71ae5a4SJacob Faibussowitsch {
1592e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1593e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1594a12d352dSMatthew G. Knepley   PetscInt       cdim;
1595e5c487bfSMatthew G. Knepley 
1596e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
15979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
15999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1600e5c487bfSMatthew G. Knepley   switch (ct) {
1601a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1602a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1603a12d352dSMatthew G. Knepley     switch (cdim) {
16049371c9d4SSatish Balay     case 1: {
1605a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1606a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1607a12d352dSMatthew G. Knepley 
16089566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
16099566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
16109566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
16119371c9d4SSatish Balay     } break;
16129371c9d4SSatish Balay     case 2: {
1613a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1614a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1615a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1616a12d352dSMatthew G. Knepley 
16179566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16189566063dSJacob Faibussowitsch       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));
16199566063dSJacob Faibussowitsch       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));
16209371c9d4SSatish Balay     } break;
1621d71ae5a4SJacob Faibussowitsch     default:
1622d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1623a12d352dSMatthew G. Knepley     }
1624a12d352dSMatthew G. Knepley     break;
1625e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
16269371c9d4SSatish Balay     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));
16279566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16289566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
16299566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1630e5c487bfSMatthew G. Knepley     break;
1631e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
16329371c9d4SSatish Balay     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));
16339371c9d4SSatish Balay     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));
16349566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16359566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
16369566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
16379566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1638e5c487bfSMatthew G. Knepley     break;
16399f4ada15SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
16409f4ada15SMatthew G. Knepley     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));
16419f4ada15SMatthew G. Knepley     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));
16429f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16439f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
16449f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
16459f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
16469f4ada15SMatthew G. Knepley     break;
1647d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_FV_GHOST:
1648d71ae5a4SJacob Faibussowitsch     break;
1649d71ae5a4SJacob Faibussowitsch   default:
1650d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1651e5c487bfSMatthew G. Knepley   }
16523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1653e5c487bfSMatthew G. Knepley }
1654e5c487bfSMatthew G. Knepley 
1655d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1656d71ae5a4SJacob Faibussowitsch {
1657e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1658e5c487bfSMatthew G. Knepley   PetscReal      centroid[2] = {0., 0.};
1659e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1660e5c487bfSMatthew G. Knepley   PetscInt       fillColor, v, e, d;
1661e5c487bfSMatthew G. Knepley 
1662e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
16639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
16649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1665e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1666e5c487bfSMatthew G. Knepley   switch (ct) {
16679371c9d4SSatish Balay   case DM_POLYTOPE_TRIANGLE: {
1668e5c487bfSMatthew G. Knepley     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1669e5c487bfSMatthew G. Knepley 
16709371c9d4SSatish Balay     for (v = 0; v < 3; ++v) {
16719371c9d4SSatish Balay       centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.;
16729371c9d4SSatish Balay       centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.;
16739371c9d4SSatish Balay     }
1674e5c487bfSMatthew G. Knepley     for (e = 0; e < 3; ++e) {
1675e5c487bfSMatthew G. Knepley       refCoords[0] = refVertices[e * 2 + 0];
1676e5c487bfSMatthew G. Knepley       refCoords[1] = refVertices[e * 2 + 1];
1677e5c487bfSMatthew G. Knepley       for (d = 1; d <= edgeDiv; ++d) {
1678e5c487bfSMatthew G. Knepley         refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv;
1679e5c487bfSMatthew G. Knepley         refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv;
1680e5c487bfSMatthew G. Knepley       }
16819566063dSJacob Faibussowitsch       PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1682e5c487bfSMatthew G. Knepley       for (d = 0; d < edgeDiv; ++d) {
16839566063dSJacob Faibussowitsch         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));
16849566063dSJacob Faibussowitsch         PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK));
1685e5c487bfSMatthew G. Knepley       }
1686e5c487bfSMatthew G. Knepley     }
16879371c9d4SSatish Balay   } break;
1688d71ae5a4SJacob Faibussowitsch   default:
1689d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1690e5c487bfSMatthew G. Knepley   }
16913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1692e5c487bfSMatthew G. Knepley }
1693e5c487bfSMatthew G. Knepley 
1694d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1695d71ae5a4SJacob Faibussowitsch {
1696e412dcbdSMatthew G. Knepley   PetscDraw    draw;
1697e412dcbdSMatthew G. Knepley   DM           cdm;
1698e412dcbdSMatthew G. Knepley   PetscSection coordSection;
1699e412dcbdSMatthew G. Knepley   Vec          coordinates;
1700c9c77995SMatthew G. Knepley   PetscReal    xyl[3], xyr[3];
1701e5c487bfSMatthew G. Knepley   PetscReal   *refCoords, *edgeCoords;
1702e5c487bfSMatthew G. Knepley   PetscBool    isnull, drawAffine = PETSC_TRUE;
1703c9c77995SMatthew G. Knepley   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4;
1704e412dcbdSMatthew G. Knepley 
1705e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
17069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
170763a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
17089566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
17099566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
17109566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
17119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
17129566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
17139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
17149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1715e412dcbdSMatthew G. Knepley 
17169566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
17179566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
17183ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
17199566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1720e412dcbdSMatthew G. Knepley 
1721c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
17229566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
17239566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1724e412dcbdSMatthew G. Knepley 
1725cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1726cf3064d3SMatthew G. Knepley     PetscScalar       *coords = NULL;
1727c9c77995SMatthew G. Knepley     const PetscScalar *coords_arr;
1728ba2698f1SMatthew G. Knepley     PetscInt           numCoords;
1729c9c77995SMatthew G. Knepley     PetscBool          isDG;
1730cf3064d3SMatthew G. Knepley 
1731c9c77995SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
17321baa6e33SBarry Smith     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
17331baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1734c9c77995SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1735cf3064d3SMatthew G. Knepley   }
17369566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
17379566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
17389566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
17399566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
17403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1741e412dcbdSMatthew G. Knepley }
1742e412dcbdSMatthew G. Knepley 
17431e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
17441e50132fSMatthew G. Knepley   #include <exodusII.h>
17456823f3c5SBlaise Bourdin   #include <petscviewerexodusii.h>
17461e50132fSMatthew G. Knepley #endif
17471e50132fSMatthew G. Knepley 
1748d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1749d71ae5a4SJacob Faibussowitsch {
17505f34f2dcSJed Brown   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1751002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
1752552f7358SJed Brown 
1753552f7358SJed Brown   PetscFunctionBegin;
1754552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1755552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
17569566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
17579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
17589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
17599566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
17609566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
17619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
17625f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1763552f7358SJed Brown   if (iascii) {
17648135c375SStefano Zampini     PetscViewerFormat format;
17659566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
17661baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
17671baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
1768c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1769c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
17709566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1771c6ccd67eSMatthew G. Knepley #else
1772c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1773552f7358SJed Brown #endif
1774e412dcbdSMatthew G. Knepley   } else if (isvtk) {
17759566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1776e412dcbdSMatthew G. Knepley   } else if (isdraw) {
17779566063dSJacob Faibussowitsch     PetscCall(DMPlexView_Draw(dm, viewer));
17788135c375SStefano Zampini   } else if (isglvis) {
17799566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
17801e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
17811e50132fSMatthew G. Knepley   } else if (isexodus) {
17826823f3c5SBlaise Bourdin     /*
17836823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
17846823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
1785da81f932SPierre Jolivet       with ID 1, containing all cells.
17866823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
17876823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
17886823f3c5SBlaise Bourdin     */
17896823f3c5SBlaise Bourdin     PetscInt numCS;
17909566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
17916823f3c5SBlaise Bourdin     if (!numCS) {
17921e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
17939566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
17949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
17959566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
17966823f3c5SBlaise Bourdin     }
17979566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
17981e50132fSMatthew G. Knepley #endif
17995f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
18005f34f2dcSJed Brown   } else if (iscgns) {
18015f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
18025f34f2dcSJed Brown #endif
18031baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1804cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
18059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1806cb3ba0daSMatthew G. Knepley   if (flg) {
1807cb3ba0daSMatthew G. Knepley     Vec ranks;
18089566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
18099566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
18109566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
1811cb3ba0daSMatthew G. Knepley   }
1812002a2709SMatthew G. Knepley   /* Optionally view a label */
18139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1814002a2709SMatthew G. Knepley   if (flg) {
1815002a2709SMatthew G. Knepley     DMLabel label;
1816002a2709SMatthew G. Knepley     Vec     val;
1817002a2709SMatthew G. Knepley 
18189566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
181928b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
18209566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
18219566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
18229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
1823002a2709SMatthew G. Knepley   }
18243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1825552f7358SJed Brown }
1826552f7358SJed Brown 
18277f96f51bSksagiyam /*@
1828a1cb98faSBarry Smith   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
18297f96f51bSksagiyam 
183020f4b53cSBarry Smith   Collective
18317f96f51bSksagiyam 
18327f96f51bSksagiyam   Input Parameters:
1833a1cb98faSBarry Smith + dm     - The `DM` whose topology is to be saved
1834a1cb98faSBarry Smith - viewer - The `PetscViewer` to save it in
18357f96f51bSksagiyam 
18367f96f51bSksagiyam   Level: advanced
18377f96f51bSksagiyam 
18381cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
18397f96f51bSksagiyam @*/
1840d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1841d71ae5a4SJacob Faibussowitsch {
18427f96f51bSksagiyam   PetscBool ishdf5;
18437f96f51bSksagiyam 
18447f96f51bSksagiyam   PetscFunctionBegin;
18457f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
18467f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
18489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
18497f96f51bSksagiyam   if (ishdf5) {
18507f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
18517f96f51bSksagiyam     PetscViewerFormat format;
18529566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
18537f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18547f96f51bSksagiyam       IS globalPointNumbering;
18557f96f51bSksagiyam 
18569566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
18579566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
18589566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
185998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
18607f96f51bSksagiyam #else
18617f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
18627f96f51bSksagiyam #endif
18637f96f51bSksagiyam   }
18649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
18653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18667f96f51bSksagiyam }
18677f96f51bSksagiyam 
186877b8e257Sksagiyam /*@
1869a1cb98faSBarry Smith   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
187077b8e257Sksagiyam 
187120f4b53cSBarry Smith   Collective
187277b8e257Sksagiyam 
187377b8e257Sksagiyam   Input Parameters:
1874a1cb98faSBarry Smith + dm     - The `DM` whose coordinates are to be saved
1875a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
187677b8e257Sksagiyam 
187777b8e257Sksagiyam   Level: advanced
187877b8e257Sksagiyam 
18791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
188077b8e257Sksagiyam @*/
1881d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1882d71ae5a4SJacob Faibussowitsch {
188377b8e257Sksagiyam   PetscBool ishdf5;
188477b8e257Sksagiyam 
188577b8e257Sksagiyam   PetscFunctionBegin;
188677b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
188777b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
18899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
189077b8e257Sksagiyam   if (ishdf5) {
189177b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
189277b8e257Sksagiyam     PetscViewerFormat format;
18939566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
189477b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18959566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
1896fe28d297SMatthew Knepley     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
189777b8e257Sksagiyam #else
189877b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
189977b8e257Sksagiyam #endif
190077b8e257Sksagiyam   }
19019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
19023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
190377b8e257Sksagiyam }
190477b8e257Sksagiyam 
1905bd6565f1Sksagiyam /*@
1906a1cb98faSBarry Smith   DMPlexLabelsView - Saves `DMPLEX` labels into a file
1907bd6565f1Sksagiyam 
190820f4b53cSBarry Smith   Collective
1909bd6565f1Sksagiyam 
1910bd6565f1Sksagiyam   Input Parameters:
1911a1cb98faSBarry Smith + dm     - The `DM` whose labels are to be saved
1912a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
1913bd6565f1Sksagiyam 
1914bd6565f1Sksagiyam   Level: advanced
1915bd6565f1Sksagiyam 
19161cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
1917bd6565f1Sksagiyam @*/
1918d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1919d71ae5a4SJacob Faibussowitsch {
1920bd6565f1Sksagiyam   PetscBool ishdf5;
1921bd6565f1Sksagiyam 
1922bd6565f1Sksagiyam   PetscFunctionBegin;
1923bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1924bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19259566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
1927bd6565f1Sksagiyam   if (ishdf5) {
1928bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
1929bd6565f1Sksagiyam     IS                globalPointNumbering;
1930bd6565f1Sksagiyam     PetscViewerFormat format;
1931bd6565f1Sksagiyam 
19329566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
1933bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
19349566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
19359566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
19369566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
193798921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1938bd6565f1Sksagiyam #else
1939bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1940bd6565f1Sksagiyam #endif
1941bd6565f1Sksagiyam   }
19429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
19433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1944bd6565f1Sksagiyam }
1945bd6565f1Sksagiyam 
1946021affd3Sksagiyam /*@
1947a1cb98faSBarry Smith   DMPlexSectionView - Saves a section associated with a `DMPLEX`
1948021affd3Sksagiyam 
194920f4b53cSBarry Smith   Collective
1950021affd3Sksagiyam 
1951021affd3Sksagiyam   Input Parameters:
1952a1cb98faSBarry Smith + dm         - The `DM` that contains the topology on which the section to be saved is defined
1953a1cb98faSBarry Smith . viewer     - The `PetscViewer` for saving
1954a1cb98faSBarry Smith - sectiondm  - The `DM` that contains the section to be saved
1955021affd3Sksagiyam 
1956021affd3Sksagiyam   Level: advanced
1957021affd3Sksagiyam 
1958021affd3Sksagiyam   Notes:
1959a1cb98faSBarry Smith   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.
1960021affd3Sksagiyam 
1961a1cb98faSBarry Smith   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1962021affd3Sksagiyam 
19631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
1964021affd3Sksagiyam @*/
1965d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1966d71ae5a4SJacob Faibussowitsch {
1967021affd3Sksagiyam   PetscBool ishdf5;
1968021affd3Sksagiyam 
1969021affd3Sksagiyam   PetscFunctionBegin;
1970021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1971021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1972021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
19739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
1975021affd3Sksagiyam   if (ishdf5) {
1976021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
19779566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1978021affd3Sksagiyam #else
1979021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1980021affd3Sksagiyam #endif
1981021affd3Sksagiyam   }
19829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
19833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1984021affd3Sksagiyam }
1985021affd3Sksagiyam 
19863e97647fSksagiyam /*@
19873e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
19883e97647fSksagiyam 
198920f4b53cSBarry Smith   Collective
19903e97647fSksagiyam 
19913e97647fSksagiyam   Input Parameters:
1992a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
1993a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
1994a1cb98faSBarry Smith . sectiondm - The `DM` that contains the global section on which vec is defined
19953e97647fSksagiyam - vec       - The global vector to be saved
19963e97647fSksagiyam 
19973e97647fSksagiyam   Level: advanced
19983e97647fSksagiyam 
19993e97647fSksagiyam   Notes:
2000a1cb98faSBarry Smith   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
20013e97647fSksagiyam 
2002a1cb98faSBarry Smith   Typical calling sequence:
2003a1cb98faSBarry Smith .vb
2004a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2005a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2006a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2007a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2008a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2009a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2010a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2011a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2012a1cb98faSBarry Smith        PetscSectionSetUp(section);
2013a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2014a1cb98faSBarry Smith        PetscSectionDestroy(&section);
2015a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2016a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2017a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2018a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2019a1cb98faSBarry Smith        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2020a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2021a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2022a1cb98faSBarry Smith        DMDestroy(&dm);
2023a1cb98faSBarry Smith .ve
20243e97647fSksagiyam 
20251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
20263e97647fSksagiyam @*/
2027d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2028d71ae5a4SJacob Faibussowitsch {
20293e97647fSksagiyam   PetscBool ishdf5;
20303e97647fSksagiyam 
20313e97647fSksagiyam   PetscFunctionBegin;
20323e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20333e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20343e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
20353e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
20363e97647fSksagiyam   /* Check consistency */
20373e97647fSksagiyam   {
20383e97647fSksagiyam     PetscSection section;
20393e97647fSksagiyam     PetscBool    includesConstraints;
20403e97647fSksagiyam     PetscInt     m, m1;
20413e97647fSksagiyam 
20429566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
20439566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
20449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
20459566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
20469566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
204763a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
20483e97647fSksagiyam   }
20499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
20513e97647fSksagiyam   if (ishdf5) {
20523e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
20539566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
20543e97647fSksagiyam #else
20553e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20563e97647fSksagiyam #endif
20573e97647fSksagiyam   }
20589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
20593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20603e97647fSksagiyam }
20613e97647fSksagiyam 
20623e97647fSksagiyam /*@
20633e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
20643e97647fSksagiyam 
206520f4b53cSBarry Smith   Collective
20663e97647fSksagiyam 
20673e97647fSksagiyam   Input Parameters:
2068a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2069a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
207020f4b53cSBarry Smith . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm`
20713e97647fSksagiyam - vec       - The local vector to be saved
20723e97647fSksagiyam 
20733e97647fSksagiyam   Level: advanced
20743e97647fSksagiyam 
2075a1cb98faSBarry Smith   Note:
207620f4b53cSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
20773e97647fSksagiyam 
2078a1cb98faSBarry Smith   Typical calling sequence:
2079a1cb98faSBarry Smith .vb
2080a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2081a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2082a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2083a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2084a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2085a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2086a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2087a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2088a1cb98faSBarry Smith        PetscSectionSetUp(section);
2089a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2090a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2091a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2092a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2093a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2094a1cb98faSBarry Smith        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2095a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2096a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2097a1cb98faSBarry Smith        DMDestroy(&dm);
2098a1cb98faSBarry Smith .ve
20993e97647fSksagiyam 
21001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
21013e97647fSksagiyam @*/
2102d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2103d71ae5a4SJacob Faibussowitsch {
21043e97647fSksagiyam   PetscBool ishdf5;
21053e97647fSksagiyam 
21063e97647fSksagiyam   PetscFunctionBegin;
21073e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21083e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21093e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
21103e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
21113e97647fSksagiyam   /* Check consistency */
21123e97647fSksagiyam   {
21133e97647fSksagiyam     PetscSection section;
21143e97647fSksagiyam     PetscBool    includesConstraints;
21153e97647fSksagiyam     PetscInt     m, m1;
21163e97647fSksagiyam 
21179566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
21189566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
21199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
21209566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
21219566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
212263a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
21233e97647fSksagiyam   }
21249566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
21263e97647fSksagiyam   if (ishdf5) {
21273e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
21289566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
21293e97647fSksagiyam #else
21303e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
21313e97647fSksagiyam #endif
21323e97647fSksagiyam   }
21339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
21343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21353e97647fSksagiyam }
21363e97647fSksagiyam 
2137d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2138d71ae5a4SJacob Faibussowitsch {
2139d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
21402c40f234SMatthew G. Knepley 
21412c40f234SMatthew G. Knepley   PetscFunctionBegin;
21422c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21432c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2145d4f5a9a0SVaclav Hapla   if (ishdf5) {
21462c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
21479c48423bSVaclav Hapla     PetscViewerFormat format;
21489566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
21499c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
21509566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2151509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21529566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
215398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
21543ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
21552c40f234SMatthew G. Knepley #else
21562c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2157552f7358SJed Brown #endif
215898921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2159552f7358SJed Brown }
2160552f7358SJed Brown 
2161ea8e1828Sksagiyam /*@
2162a1cb98faSBarry Smith   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2163ea8e1828Sksagiyam 
216420f4b53cSBarry Smith   Collective
2165ea8e1828Sksagiyam 
2166ea8e1828Sksagiyam   Input Parameters:
2167a1cb98faSBarry Smith + dm                - The `DM` into which the topology is loaded
2168a1cb98faSBarry Smith - viewer            - The `PetscViewer` for the saved topology
2169ea8e1828Sksagiyam 
21702fe279fdSBarry Smith   Output Parameter:
217120f4b53cSBarry Smith . 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
2172dec9e869Sksagiyam 
2173ea8e1828Sksagiyam   Level: advanced
2174ea8e1828Sksagiyam 
21751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2176a1cb98faSBarry Smith           `PetscViewer`, `PetscSF`
2177ea8e1828Sksagiyam @*/
2178d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2179d71ae5a4SJacob Faibussowitsch {
2180ea8e1828Sksagiyam   PetscBool ishdf5;
2181ea8e1828Sksagiyam 
2182ea8e1828Sksagiyam   PetscFunctionBegin;
2183ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2184ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2185f84dd6b4Sksagiyam   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
21869566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2188ea8e1828Sksagiyam   if (ishdf5) {
2189ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2190ea8e1828Sksagiyam     PetscViewerFormat format;
21919566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2192ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21939566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
219498921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2195ea8e1828Sksagiyam #else
2196ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2197ea8e1828Sksagiyam #endif
2198ea8e1828Sksagiyam   }
21999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
22003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2201ea8e1828Sksagiyam }
2202ea8e1828Sksagiyam 
22033e701f1cSksagiyam /*@
2204a1cb98faSBarry Smith   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
22053e701f1cSksagiyam 
220620f4b53cSBarry Smith   Collective
22073e701f1cSksagiyam 
22083e701f1cSksagiyam   Input Parameters:
2209a1cb98faSBarry Smith + dm     - The `DM` into which the coordinates are loaded
2210a1cb98faSBarry Smith . viewer - The `PetscViewer` for the saved coordinates
2211a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
22123e701f1cSksagiyam 
22133e701f1cSksagiyam   Level: advanced
22143e701f1cSksagiyam 
22151cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2216a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
22173e701f1cSksagiyam @*/
2218d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2219d71ae5a4SJacob Faibussowitsch {
22203e701f1cSksagiyam   PetscBool ishdf5;
22213e701f1cSksagiyam 
22223e701f1cSksagiyam   PetscFunctionBegin;
22233e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22243e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2225c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
22269566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22279566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
22283e701f1cSksagiyam   if (ishdf5) {
22293e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
22303e701f1cSksagiyam     PetscViewerFormat format;
22319566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
22323e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
22339566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
223498921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
22353e701f1cSksagiyam #else
22363e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
22373e701f1cSksagiyam #endif
22383e701f1cSksagiyam   }
22399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
22403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22413e701f1cSksagiyam }
22423e701f1cSksagiyam 
2243b08ad5deSksagiyam /*@
2244a1cb98faSBarry Smith   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2245b08ad5deSksagiyam 
224620f4b53cSBarry Smith   Collective
2247b08ad5deSksagiyam 
2248b08ad5deSksagiyam   Input Parameters:
2249a1cb98faSBarry Smith + dm     - The `DM` into which the labels are loaded
2250a1cb98faSBarry Smith . viewer - The `PetscViewer` for the saved labels
225120f4b53cSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2252b08ad5deSksagiyam 
2253b08ad5deSksagiyam   Level: advanced
2254b08ad5deSksagiyam 
2255a1cb98faSBarry Smith   Note:
2256a1cb98faSBarry Smith   The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs.
2257e6368b79SVaclav Hapla 
22581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2259a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
2260b08ad5deSksagiyam @*/
2261d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2262d71ae5a4SJacob Faibussowitsch {
2263b08ad5deSksagiyam   PetscBool ishdf5;
2264b08ad5deSksagiyam 
2265b08ad5deSksagiyam   PetscFunctionBegin;
2266b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2267b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2268e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
22699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22709566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2271b08ad5deSksagiyam   if (ishdf5) {
2272b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2273b08ad5deSksagiyam     PetscViewerFormat format;
2274b08ad5deSksagiyam 
22759566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2276b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
22779566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
227898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2279b08ad5deSksagiyam #else
2280b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2281b08ad5deSksagiyam #endif
2282b08ad5deSksagiyam   }
22839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
22843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2285b08ad5deSksagiyam }
2286b08ad5deSksagiyam 
2287f84dd6b4Sksagiyam /*@
2288a1cb98faSBarry Smith   DMPlexSectionLoad - Loads section into a `DMPLEX`
2289f84dd6b4Sksagiyam 
229020f4b53cSBarry Smith   Collective
2291f84dd6b4Sksagiyam 
2292f84dd6b4Sksagiyam   Input Parameters:
2293a1cb98faSBarry Smith + dm          - The `DM` that represents the topology
2294a1cb98faSBarry Smith . viewer      - The `PetscViewer` that represents the on-disk section (sectionA)
2295a1cb98faSBarry Smith . sectiondm   - The `DM` into which the on-disk section (sectionA) is migrated
2296a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2297f84dd6b4Sksagiyam 
2298f84dd6b4Sksagiyam   Output Parameters
229920f4b53cSBarry Smith + 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)
230020f4b53cSBarry Smith - 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)
2301f84dd6b4Sksagiyam 
2302f84dd6b4Sksagiyam   Level: advanced
2303f84dd6b4Sksagiyam 
2304f84dd6b4Sksagiyam   Notes:
230520f4b53cSBarry Smith   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.
2306f84dd6b4Sksagiyam 
230720f4b53cSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2308f84dd6b4Sksagiyam 
230920f4b53cSBarry Smith   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.
2310f84dd6b4Sksagiyam 
2311f84dd6b4Sksagiyam   Example using 2 processes:
2312a1cb98faSBarry Smith .vb
2313a1cb98faSBarry Smith   NX (number of points on dm): 4
2314a1cb98faSBarry Smith   sectionA                   : the on-disk section
2315a1cb98faSBarry Smith   vecA                       : a vector associated with sectionA
2316a1cb98faSBarry Smith   sectionB                   : sectiondm's local section constructed in this function
2317a1cb98faSBarry Smith   vecB (local)               : a vector associated with sectiondm's local section
2318a1cb98faSBarry Smith   vecB (global)              : a vector associated with sectiondm's global section
2319f84dd6b4Sksagiyam 
2320a1cb98faSBarry Smith                                      rank 0    rank 1
2321a1cb98faSBarry Smith   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2322a1cb98faSBarry Smith   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2323a1cb98faSBarry Smith   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2324a1cb98faSBarry Smith   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2325a1cb98faSBarry Smith   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2326a1cb98faSBarry Smith   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2327a1cb98faSBarry Smith   sectionB->atlasDof             :     1 0 1 | 1 3
2328a1cb98faSBarry Smith   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2329a1cb98faSBarry Smith   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2330a1cb98faSBarry Smith   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2331a1cb98faSBarry Smith .ve
2332a1cb98faSBarry Smith   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2333a1cb98faSBarry Smith 
23341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2335f84dd6b4Sksagiyam @*/
2336d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2337d71ae5a4SJacob Faibussowitsch {
2338f84dd6b4Sksagiyam   PetscBool ishdf5;
2339f84dd6b4Sksagiyam 
2340f84dd6b4Sksagiyam   PetscFunctionBegin;
2341f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2342f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2343f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2344f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2345f84dd6b4Sksagiyam   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2346f84dd6b4Sksagiyam   if (localDofSF) PetscValidPointer(localDofSF, 6);
23479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2349f84dd6b4Sksagiyam   if (ishdf5) {
2350f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
23519566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2352f84dd6b4Sksagiyam #else
2353f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2354f84dd6b4Sksagiyam #endif
2355f84dd6b4Sksagiyam   }
23569566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
23573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2358f84dd6b4Sksagiyam }
2359f84dd6b4Sksagiyam 
23608be3dfe1Sksagiyam /*@
23618be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
23628be3dfe1Sksagiyam 
236320f4b53cSBarry Smith   Collective
23648be3dfe1Sksagiyam 
23658be3dfe1Sksagiyam   Input Parameters:
2366a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2367a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
2368a1cb98faSBarry Smith . sectiondm - The `DM` that contains the global section on which vec is defined
2369a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
23708be3dfe1Sksagiyam - vec       - The global vector to set values of
23718be3dfe1Sksagiyam 
23728be3dfe1Sksagiyam   Level: advanced
23738be3dfe1Sksagiyam 
23748be3dfe1Sksagiyam   Notes:
2375a1cb98faSBarry Smith   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
23768be3dfe1Sksagiyam 
2377a1cb98faSBarry Smith   Typical calling sequence:
2378a1cb98faSBarry Smith .vb
2379a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2380a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2381a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2382a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2383a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2384a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2385a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2386a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2387a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2388a1cb98faSBarry Smith        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2389a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2390a1cb98faSBarry Smith        PetscSFDestroy(&gsf);
2391a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2392a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2393a1cb98faSBarry Smith        DMDestroy(&dm);
2394a1cb98faSBarry Smith .ve
23958be3dfe1Sksagiyam 
23961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2397a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
23988be3dfe1Sksagiyam @*/
2399d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2400d71ae5a4SJacob Faibussowitsch {
24018be3dfe1Sksagiyam   PetscBool ishdf5;
24028be3dfe1Sksagiyam 
24038be3dfe1Sksagiyam   PetscFunctionBegin;
24048be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24058be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24068be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24078be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
24088be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
24098be3dfe1Sksagiyam   /* Check consistency */
24108be3dfe1Sksagiyam   {
24118be3dfe1Sksagiyam     PetscSection section;
24128be3dfe1Sksagiyam     PetscBool    includesConstraints;
24138be3dfe1Sksagiyam     PetscInt     m, m1;
24148be3dfe1Sksagiyam 
24159566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24169566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
24179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24189566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24199566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
242063a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
24218be3dfe1Sksagiyam   }
24229566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
24248be3dfe1Sksagiyam   if (ishdf5) {
24258be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
24269566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
24278be3dfe1Sksagiyam #else
24288be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24298be3dfe1Sksagiyam #endif
24308be3dfe1Sksagiyam   }
24319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
24323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24338be3dfe1Sksagiyam }
24348be3dfe1Sksagiyam 
24358be3dfe1Sksagiyam /*@
24368be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
24378be3dfe1Sksagiyam 
243820f4b53cSBarry Smith   Collective
24398be3dfe1Sksagiyam 
24408be3dfe1Sksagiyam   Input Parameters:
2441a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2442a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
2443a1cb98faSBarry Smith . sectiondm - The `DM` that contains the local section on which vec is defined
2444a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
24458be3dfe1Sksagiyam - vec       - The local vector to set values of
24468be3dfe1Sksagiyam 
24478be3dfe1Sksagiyam   Level: advanced
24488be3dfe1Sksagiyam 
24498be3dfe1Sksagiyam   Notes:
245020f4b53cSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
24518be3dfe1Sksagiyam 
2452a1cb98faSBarry Smith   Typical calling sequence:
2453a1cb98faSBarry Smith .vb
2454a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2455a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2456a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2457a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2458a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2459a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2460a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2461a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2462a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2463a1cb98faSBarry Smith        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2464a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2465a1cb98faSBarry Smith        PetscSFDestroy(&lsf);
2466a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2467a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2468a1cb98faSBarry Smith        DMDestroy(&dm);
2469a1cb98faSBarry Smith .ve
24708be3dfe1Sksagiyam 
24711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2472a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
24738be3dfe1Sksagiyam @*/
2474d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2475d71ae5a4SJacob Faibussowitsch {
24768be3dfe1Sksagiyam   PetscBool ishdf5;
24778be3dfe1Sksagiyam 
24788be3dfe1Sksagiyam   PetscFunctionBegin;
24798be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24808be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24818be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24828be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
24838be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
24848be3dfe1Sksagiyam   /* Check consistency */
24858be3dfe1Sksagiyam   {
24868be3dfe1Sksagiyam     PetscSection section;
24878be3dfe1Sksagiyam     PetscBool    includesConstraints;
24888be3dfe1Sksagiyam     PetscInt     m, m1;
24898be3dfe1Sksagiyam 
24909566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24919566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
24929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24939566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24949566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
249563a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
24968be3dfe1Sksagiyam   }
24979566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
24998be3dfe1Sksagiyam   if (ishdf5) {
25008be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
25019566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
25028be3dfe1Sksagiyam #else
25038be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
25048be3dfe1Sksagiyam #endif
25058be3dfe1Sksagiyam   }
25069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
25073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25088be3dfe1Sksagiyam }
25098be3dfe1Sksagiyam 
2510d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2511d71ae5a4SJacob Faibussowitsch {
2512552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2513552f7358SJed Brown 
2514552f7358SJed Brown   PetscFunctionBegin;
25159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
25169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
25179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
25189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
25192e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL));
25202e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
25212e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
25222e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
25232e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
25246bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
25256bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2526c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2527c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
25285f06a3ddSJed Brown   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
25293ba16761SJacob Faibussowitsch   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
25309566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
25319566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
25329566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
25339566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
25349566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
25359566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
253621027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
25379f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
25389566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
25399566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
25409566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
25411d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
25429566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
25439566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
25449566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
25459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
25469566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
25474e2e9504SJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.face_sf));
25486725e60dSJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
25496725e60dSJed Brown   PetscCall(ISDestroy(&mesh->periodic.periodic_points));
25509566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
25519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
25529566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
25539566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
25549566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
25559566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
25569566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
25579566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
25589566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
25599566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
25609566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2561552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
25629566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
25633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2564552f7358SJed Brown }
2565552f7358SJed Brown 
2566d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2567d71ae5a4SJacob Faibussowitsch {
25688d1174e4SMatthew G. Knepley   PetscSection           sectionGlobal;
2569acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
25709fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2571837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2572b412c318SBarry Smith   MatType                mtype;
25731428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2574552f7358SJed Brown 
2575552f7358SJed Brown   PetscFunctionBegin;
25769566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2577b412c318SBarry Smith   mtype = dm->mattype;
25789566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
25799566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
25809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
25819fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
25829566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
25839566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
25849566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
25859566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
25869566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2587acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
25889566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
25899566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
25909566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
25919566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
25929566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
25939566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
25949566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
25959566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2596552f7358SJed Brown   if (!isShell) {
2597837628f4SStefano Zampini     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
25989fca9976SJed Brown     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2599863027abSJed Brown     PetscInt  pStart, pEnd, p, dof, cdof, num_fields;
2600552f7358SJed Brown 
26019566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
26029fca9976SJed Brown 
26039fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
26049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2605863027abSJed Brown     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2606e432b41dSStefano Zampini     for (p = pStart; p < pEnd; ++p) {
2607863027abSJed Brown       switch (dm->blocking_type) {
26080e762ea3SJed Brown       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
26099fca9976SJed Brown         PetscInt bdof, offset;
2610a9d99c84SMatthew G. Knepley 
26119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
26129fca9976SJed Brown         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
26139566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
26149371c9d4SSatish Balay         for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof;
26151d17a0a3SMatthew G. Knepley         dof  = dof < 0 ? -(dof + 1) : dof;
26161d17a0a3SMatthew G. Knepley         bdof = cdof && (dof - cdof) ? 1 : dof;
26171d17a0a3SMatthew G. Knepley         if (dof) {
26189371c9d4SSatish Balay           if (bs < 0) {
26199371c9d4SSatish Balay             bs = bdof;
26209371c9d4SSatish Balay           } else if (bs != bdof) {
26219371c9d4SSatish Balay             bs = 1;
26229371c9d4SSatish Balay           }
2623552f7358SJed Brown         }
2624863027abSJed Brown       } break;
2625863027abSJed Brown       case DM_BLOCKING_FIELD_NODE: {
2626863027abSJed Brown         for (PetscInt field = 0; field < num_fields; field++) {
2627863027abSJed Brown           PetscInt num_comp, bdof, offset;
2628863027abSJed Brown           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2629863027abSJed Brown           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2630863027abSJed Brown           if (dof < 0) continue;
2631863027abSJed Brown           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2632863027abSJed Brown           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2633863027abSJed Brown           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);
2634863027abSJed Brown           PetscInt num_nodes = dof / num_comp;
2635863027abSJed Brown           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2636863027abSJed Brown           // Handle possibly constant block size (unlikely)
2637863027abSJed Brown           bdof = cdof && (dof - cdof) ? 1 : dof;
2638863027abSJed Brown           if (dof) {
2639863027abSJed Brown             if (bs < 0) {
2640863027abSJed Brown               bs = bdof;
2641863027abSJed Brown             } else if (bs != bdof) {
2642863027abSJed Brown               bs = 1;
2643863027abSJed Brown             }
2644863027abSJed Brown           }
2645863027abSJed Brown         }
2646863027abSJed Brown       } break;
2647863027abSJed Brown       }
26482a28c762SMatthew G Knepley     }
26492a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2650e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2651e432b41dSStefano Zampini     bsLocal[1] = bs;
26529566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2653e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2654e432b41dSStefano Zampini     else bs = bsMinMax[0];
26556fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
26569566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
26570682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
26589566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
26599566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
26600682b8bbSJed Brown     } else {
26619566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
26629566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
26639566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2664552f7358SJed Brown     }
26659fca9976SJed Brown     { // Consolidate blocks
26669fca9976SJed Brown       PetscInt nblocks = 0;
26679fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
26689fca9976SJed Brown         if (pblocks[i] == 0) continue;
26699fca9976SJed Brown         pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2670ad540459SPierre Jolivet         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]);
26719fca9976SJed Brown       }
26729fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
26739fca9976SJed Brown     }
26749fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2675aa0f6e3cSJed Brown   }
26769566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
26773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2678552f7358SJed Brown }
2679552f7358SJed Brown 
26807cd05799SMatthew G. Knepley /*@
2681a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2682be36d101SStefano Zampini 
2683a1cb98faSBarry Smith   Not Collective
2684be36d101SStefano Zampini 
2685be36d101SStefano Zampini   Input Parameter:
2686a1cb98faSBarry Smith . mesh - The `DMPLEX`
2687be36d101SStefano Zampini 
26882fe279fdSBarry Smith   Output Parameter:
2689be36d101SStefano Zampini . subsection - The subdomain section
2690be36d101SStefano Zampini 
2691be36d101SStefano Zampini   Level: developer
2692be36d101SStefano Zampini 
26931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
26947cd05799SMatthew G. Knepley @*/
2695d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2696d71ae5a4SJacob Faibussowitsch {
2697be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
2698be36d101SStefano Zampini 
2699be36d101SStefano Zampini   PetscFunctionBegin;
2700be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2701be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2702be36d101SStefano Zampini     PetscSection section;
2703be36d101SStefano Zampini     PetscSF      sf;
2704be36d101SStefano Zampini 
27059566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
27069566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
27079566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
27089566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2709be36d101SStefano Zampini   }
2710be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
27113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2712be36d101SStefano Zampini }
2713be36d101SStefano Zampini 
2714552f7358SJed Brown /*@
271520f4b53cSBarry Smith   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
2716552f7358SJed Brown 
2717a1cb98faSBarry Smith   Not Collective
2718552f7358SJed Brown 
2719552f7358SJed Brown   Input Parameter:
2720a1cb98faSBarry Smith . mesh - The `DMPLEX`
2721552f7358SJed Brown 
2722552f7358SJed Brown   Output Parameters:
2723552f7358SJed Brown + pStart - The first mesh point
2724552f7358SJed Brown - pEnd   - The upper bound for mesh points
2725552f7358SJed Brown 
2726552f7358SJed Brown   Level: beginner
2727552f7358SJed Brown 
27281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2729552f7358SJed Brown @*/
2730d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2731d71ae5a4SJacob Faibussowitsch {
2732552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2733552f7358SJed Brown 
2734552f7358SJed Brown   PetscFunctionBegin;
2735552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27369f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
27379f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
27383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2739552f7358SJed Brown }
2740552f7358SJed Brown 
2741552f7358SJed Brown /*@
274220f4b53cSBarry Smith   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
2743552f7358SJed Brown 
2744a1cb98faSBarry Smith   Not Collective
2745552f7358SJed Brown 
2746552f7358SJed Brown   Input Parameters:
2747a1cb98faSBarry Smith + mesh - The `DMPLEX`
2748552f7358SJed Brown . pStart - The first mesh point
2749552f7358SJed Brown - pEnd   - The upper bound for mesh points
2750552f7358SJed Brown 
2751552f7358SJed Brown   Level: beginner
2752552f7358SJed Brown 
27531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2754552f7358SJed Brown @*/
2755d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2756d71ae5a4SJacob Faibussowitsch {
2757552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2758552f7358SJed Brown 
2759552f7358SJed Brown   PetscFunctionBegin;
2760552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
27629566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
276321027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
27643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2765552f7358SJed Brown }
2766552f7358SJed Brown 
2767552f7358SJed Brown /*@
2768eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2769552f7358SJed Brown 
2770a1cb98faSBarry Smith   Not Collective
2771552f7358SJed Brown 
2772552f7358SJed Brown   Input Parameters:
2773a1cb98faSBarry Smith + mesh - The `DMPLEX`
2774a1cb98faSBarry Smith - p - The point, which must lie in the chart set with `DMPlexSetChart()`
2775552f7358SJed Brown 
2776552f7358SJed Brown   Output Parameter:
277720f4b53cSBarry Smith . size - The cone size for point `p`
2778552f7358SJed Brown 
2779552f7358SJed Brown   Level: beginner
2780552f7358SJed Brown 
27811cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2782552f7358SJed Brown @*/
2783d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2784d71ae5a4SJacob Faibussowitsch {
2785552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2786552f7358SJed Brown 
2787552f7358SJed Brown   PetscFunctionBegin;
2788552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2789dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
27909f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
27919f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
27923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2793552f7358SJed Brown }
2794552f7358SJed Brown 
2795552f7358SJed Brown /*@
2796eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2797552f7358SJed Brown 
2798a1cb98faSBarry Smith   Not Collective
2799552f7358SJed Brown 
2800552f7358SJed Brown   Input Parameters:
2801a1cb98faSBarry Smith + mesh - The `DMPLEX`
2802a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
280320f4b53cSBarry Smith - size - The cone size for point `p`
2804552f7358SJed Brown 
2805552f7358SJed Brown   Level: beginner
2806552f7358SJed Brown 
2807a1cb98faSBarry Smith   Note:
2808a1cb98faSBarry Smith   This should be called after `DMPlexSetChart()`.
2809a1cb98faSBarry Smith 
28101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2811552f7358SJed Brown @*/
2812d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2813d71ae5a4SJacob Faibussowitsch {
2814552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2815552f7358SJed Brown 
2816552f7358SJed Brown   PetscFunctionBegin;
2817552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28189f4ada15SMatthew G. Knepley   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
28199566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
28203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2821552f7358SJed Brown }
2822552f7358SJed Brown 
2823552f7358SJed Brown /*@C
2824eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2825552f7358SJed Brown 
2826a1cb98faSBarry Smith   Not Collective
2827552f7358SJed Brown 
2828552f7358SJed Brown   Input Parameters:
2829a1cb98faSBarry Smith + dm - The `DMPLEX`
2830a1cb98faSBarry Smith - p - The point, which must lie in the chart set with `DMPlexSetChart()`
2831552f7358SJed Brown 
2832552f7358SJed Brown   Output Parameter:
283320f4b53cSBarry Smith . cone - An array of points which are on the in-edges for point `p`
2834552f7358SJed Brown 
2835552f7358SJed Brown   Level: beginner
2836552f7358SJed Brown 
2837a1cb98faSBarry Smith   Fortran Note:
2838a1cb98faSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
2839a1cb98faSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
28403813dfbdSMatthew G Knepley 
28411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
2842552f7358SJed Brown @*/
2843d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2844d71ae5a4SJacob Faibussowitsch {
2845552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2846552f7358SJed Brown   PetscInt off;
2847552f7358SJed Brown 
2848552f7358SJed Brown   PetscFunctionBegin;
2849552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2850552f7358SJed Brown   PetscValidPointer(cone, 3);
28519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
2852552f7358SJed Brown   *cone = &mesh->cones[off];
28533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2854552f7358SJed Brown }
2855552f7358SJed Brown 
28560ce7577fSVaclav Hapla /*@C
28570ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
28580ce7577fSVaclav Hapla 
2859a1cb98faSBarry Smith   Not Collective
28600ce7577fSVaclav Hapla 
28610ce7577fSVaclav Hapla   Input Parameters:
2862a1cb98faSBarry Smith + dm - The `DMPLEX`
2863a1cb98faSBarry Smith - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
28640ce7577fSVaclav Hapla 
2865d8d19677SJose E. Roman   Output Parameters:
286620f4b53cSBarry Smith + pConesSection - `PetscSection` describing the layout of `pCones`
286720f4b53cSBarry Smith - pCones - An array of points which are on the in-edges for the point set `p`
28680ce7577fSVaclav Hapla 
28690ce7577fSVaclav Hapla   Level: intermediate
28700ce7577fSVaclav Hapla 
28711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
28720ce7577fSVaclav Hapla @*/
2873d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2874d71ae5a4SJacob Faibussowitsch {
28750ce7577fSVaclav Hapla   PetscSection cs, newcs;
28760ce7577fSVaclav Hapla   PetscInt    *cones;
28770ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
28780ce7577fSVaclav Hapla   PetscInt     n;
28790ce7577fSVaclav Hapla 
28800ce7577fSVaclav Hapla   PetscFunctionBegin;
28819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
28829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
28839566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
28840ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
28850ce7577fSVaclav Hapla   if (pCones) {
28869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
28879566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
28880ce7577fSVaclav Hapla   }
28893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28900ce7577fSVaclav Hapla }
28910ce7577fSVaclav Hapla 
2892af9eab45SVaclav Hapla /*@
2893af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2894d4636a37SVaclav Hapla 
2895a1cb98faSBarry Smith   Not Collective
2896d4636a37SVaclav Hapla 
2897d4636a37SVaclav Hapla   Input Parameters:
2898a1cb98faSBarry Smith + dm - The `DMPLEX`
2899a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
2900d4636a37SVaclav Hapla 
2901d4636a37SVaclav Hapla   Output Parameter:
2902af9eab45SVaclav Hapla . expandedPoints - An array of vertices recursively expanded from input points
2903d4636a37SVaclav Hapla 
2904d4636a37SVaclav Hapla   Level: advanced
2905d4636a37SVaclav Hapla 
2906af9eab45SVaclav Hapla   Notes:
290720f4b53cSBarry Smith   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
2908af9eab45SVaclav Hapla 
2909a1cb98faSBarry Smith   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
2910a1cb98faSBarry Smith 
29111cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
2912a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`
2913d4636a37SVaclav Hapla @*/
2914d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2915d71ae5a4SJacob Faibussowitsch {
2916af9eab45SVaclav Hapla   IS      *expandedPointsAll;
2917af9eab45SVaclav Hapla   PetscInt depth;
2918d4636a37SVaclav Hapla 
2919d4636a37SVaclav Hapla   PetscFunctionBegin;
2920af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2921af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2922af9eab45SVaclav Hapla   PetscValidPointer(expandedPoints, 3);
29239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2924af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
29259566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
29269566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
29273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2928af9eab45SVaclav Hapla }
2929af9eab45SVaclav Hapla 
2930af9eab45SVaclav Hapla /*@
2931af9eab45SVaclav Hapla   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).
2932af9eab45SVaclav Hapla 
2933a1cb98faSBarry Smith   Not Collective
2934af9eab45SVaclav Hapla 
2935af9eab45SVaclav Hapla   Input Parameters:
2936a1cb98faSBarry Smith + dm - The `DMPLEX`
2937a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
2938af9eab45SVaclav Hapla 
2939d8d19677SJose E. Roman   Output Parameters:
2940a1cb98faSBarry Smith + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
2941af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
2942af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
2943af9eab45SVaclav Hapla 
2944af9eab45SVaclav Hapla   Level: advanced
2945af9eab45SVaclav Hapla 
2946af9eab45SVaclav Hapla   Notes:
2947a1cb98faSBarry Smith   Like `DMPlexGetConeTuple()` but recursive.
2948af9eab45SVaclav Hapla 
294920f4b53cSBarry Smith   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.
2950af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2951af9eab45SVaclav Hapla 
295220f4b53cSBarry Smith   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:
295320f4b53cSBarry Smith   (1) DAG points in expandedPoints[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
295420f4b53cSBarry Smith   (2) DAG points in expandedPoints[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
2955af9eab45SVaclav Hapla 
29561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
2957a1cb98faSBarry Smith           `DMPlexGetDepth()`, `PetscSection`, `IS`
2958af9eab45SVaclav Hapla @*/
2959d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2960d71ae5a4SJacob Faibussowitsch {
2961af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
2962af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
2963af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
2964af9eab45SVaclav Hapla   IS             *expandedPoints_;
2965af9eab45SVaclav Hapla   PetscSection   *sections_;
2966af9eab45SVaclav Hapla 
2967af9eab45SVaclav Hapla   PetscFunctionBegin;
2968af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2969af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2970af9eab45SVaclav Hapla   if (depth) PetscValidIntPointer(depth, 3);
2971af9eab45SVaclav Hapla   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2972af9eab45SVaclav Hapla   if (sections) PetscValidPointer(sections, 5);
29739566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
29749566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
29759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
29769566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
29779566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
2978af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
2979af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
29809566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
29819566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
2982af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
29839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
2984af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
29859566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
29869566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
2987af9eab45SVaclav Hapla       } else {
29889566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
2989af9eab45SVaclav Hapla       }
2990af9eab45SVaclav Hapla     }
29919566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
29929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
29939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
2994af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
29959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
29969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
2997af9eab45SVaclav Hapla       if (cn > 1) {
29989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
29999566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3000af9eab45SVaclav Hapla       } else {
3001af9eab45SVaclav Hapla         newarr[co] = arr[i];
3002af9eab45SVaclav Hapla       }
3003af9eab45SVaclav Hapla     }
30049566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3005af9eab45SVaclav Hapla     arr = newarr;
3006af9eab45SVaclav Hapla     n   = newn;
3007af9eab45SVaclav Hapla   }
30089566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
3009af9eab45SVaclav Hapla   *depth = depth_;
3010af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
3011af9eab45SVaclav Hapla   else {
30129566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
30139566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
3014af9eab45SVaclav Hapla   }
3015af9eab45SVaclav Hapla   if (sections) *sections = sections_;
3016af9eab45SVaclav Hapla   else {
30179566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
30189566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
3019af9eab45SVaclav Hapla   }
30203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3021af9eab45SVaclav Hapla }
3022af9eab45SVaclav Hapla 
3023af9eab45SVaclav Hapla /*@
3024a1cb98faSBarry Smith   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3025af9eab45SVaclav Hapla 
3026a1cb98faSBarry Smith   Not Collective
3027af9eab45SVaclav Hapla 
3028af9eab45SVaclav Hapla   Input Parameters:
3029a1cb98faSBarry Smith + dm - The `DMPLEX`
3030a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3031af9eab45SVaclav Hapla 
3032d8d19677SJose E. Roman   Output Parameters:
3033a1cb98faSBarry Smith + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3034af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3035af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
3036af9eab45SVaclav Hapla 
3037af9eab45SVaclav Hapla   Level: advanced
3038af9eab45SVaclav Hapla 
3039a1cb98faSBarry Smith   Note:
3040a1cb98faSBarry Smith   See `DMPlexGetConeRecursive()`
3041af9eab45SVaclav Hapla 
30421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3043a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`, `PetscSection`
3044af9eab45SVaclav Hapla @*/
3045d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3046d71ae5a4SJacob Faibussowitsch {
3047af9eab45SVaclav Hapla   PetscInt d, depth_;
3048af9eab45SVaclav Hapla 
3049af9eab45SVaclav Hapla   PetscFunctionBegin;
30509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
30511dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3052af9eab45SVaclav Hapla   if (depth) *depth = 0;
3053af9eab45SVaclav Hapla   if (expandedPoints) {
30549566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
30559566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3056af9eab45SVaclav Hapla   }
3057af9eab45SVaclav Hapla   if (sections) {
30589566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
30599566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3060af9eab45SVaclav Hapla   }
30613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3062d4636a37SVaclav Hapla }
3063d4636a37SVaclav Hapla 
3064552f7358SJed Brown /*@
306592371b87SBarry Smith   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
3066552f7358SJed Brown 
3067a1cb98faSBarry Smith   Not Collective
3068552f7358SJed Brown 
3069552f7358SJed Brown   Input Parameters:
3070a1cb98faSBarry Smith + mesh - The `DMPLEX`
3071a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
307220f4b53cSBarry Smith - cone - An array of points which are on the in-edges for point `p`
3073552f7358SJed Brown 
3074552f7358SJed Brown   Level: beginner
3075552f7358SJed Brown 
3076a1cb98faSBarry Smith   Note:
3077a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3078a1cb98faSBarry Smith 
30791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3080552f7358SJed Brown @*/
3081d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3082d71ae5a4SJacob Faibussowitsch {
3083552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3084552f7358SJed Brown   PetscInt dof, off, c;
3085552f7358SJed Brown 
3086552f7358SJed Brown   PetscFunctionBegin;
3087552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3089dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(cone, 3);
30909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3091db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3092db485b19SStefano Zampini     PetscInt pStart, pEnd;
3093db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
309463a3b9bcSJacob Faibussowitsch     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);
3095552f7358SJed Brown     for (c = 0; c < dof; ++c) {
309663a3b9bcSJacob Faibussowitsch       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);
3097552f7358SJed Brown       mesh->cones[off + c] = cone[c];
3098552f7358SJed Brown     }
3099db485b19SStefano Zampini   } else {
3100db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3101db485b19SStefano Zampini   }
31023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3103552f7358SJed Brown }
3104552f7358SJed Brown 
3105552f7358SJed Brown /*@C
3106eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3107552f7358SJed Brown 
3108a1cb98faSBarry Smith   Not Collective
3109552f7358SJed Brown 
3110552f7358SJed Brown   Input Parameters:
3111a1cb98faSBarry Smith + mesh - The `DMPLEX`
3112a1cb98faSBarry Smith - p - The point, which must lie in the chart set with `DMPlexSetChart()`
3113552f7358SJed Brown 
3114552f7358SJed Brown   Output Parameter:
311520f4b53cSBarry Smith . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
3116b5a892a1SMatthew G. Knepley                     integer giving the prescription for cone traversal.
3117552f7358SJed Brown 
3118552f7358SJed Brown   Level: beginner
3119552f7358SJed Brown 
3120a1cb98faSBarry Smith   Note:
3121b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3122b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3123a1cb98faSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3124b5a892a1SMatthew G. Knepley   with the identity.
3125b5a892a1SMatthew G. Knepley 
3126a1cb98faSBarry Smith   Fortran Note:
3127a1cb98faSBarry Smith   You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3128a1cb98faSBarry Smith   `DMPlexRestoreConeOrientation()` is not needed/available in C.
31293813dfbdSMatthew G Knepley 
31301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3131552f7358SJed Brown @*/
3132d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3133d71ae5a4SJacob Faibussowitsch {
3134552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3135552f7358SJed Brown   PetscInt off;
3136552f7358SJed Brown 
3137552f7358SJed Brown   PetscFunctionBegin;
3138552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
313976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3140552f7358SJed Brown     PetscInt dof;
31419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3142552f7358SJed Brown     if (dof) PetscValidPointer(coneOrientation, 3);
3143552f7358SJed Brown   }
31449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
31450d644c17SKarl Rupp 
3146552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
31473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3148552f7358SJed Brown }
3149552f7358SJed Brown 
3150552f7358SJed Brown /*@
3151eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3152552f7358SJed Brown 
3153a1cb98faSBarry Smith   Not Collective
3154552f7358SJed Brown 
3155552f7358SJed Brown   Input Parameters:
3156a1cb98faSBarry Smith + mesh - The `DMPLEX`
3157a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3158b5a892a1SMatthew G. Knepley - coneOrientation - An array of orientations
3159b5a892a1SMatthew G. Knepley 
3160552f7358SJed Brown   Level: beginner
3161552f7358SJed Brown 
3162a1cb98faSBarry Smith   Notes:
3163a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3164a1cb98faSBarry Smith 
3165a1cb98faSBarry Smith   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3166a1cb98faSBarry Smith 
31671cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3168552f7358SJed Brown @*/
3169d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3170d71ae5a4SJacob Faibussowitsch {
3171552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3172552f7358SJed Brown   PetscInt pStart, pEnd;
3173552f7358SJed Brown   PetscInt dof, off, c;
3174552f7358SJed Brown 
3175552f7358SJed Brown   PetscFunctionBegin;
3176552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3178dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(coneOrientation, 3);
31799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3180db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3181db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
318263a3b9bcSJacob Faibussowitsch     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);
3183552f7358SJed Brown     for (c = 0; c < dof; ++c) {
3184552f7358SJed Brown       PetscInt cdof, o = coneOrientation[c];
3185552f7358SJed Brown 
31869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
31871dca8a05SBarry Smith       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);
3188552f7358SJed Brown       mesh->coneOrientations[off + c] = o;
3189552f7358SJed Brown     }
3190db485b19SStefano Zampini   } else {
3191db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3192db485b19SStefano Zampini   }
31933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3194552f7358SJed Brown }
3195552f7358SJed Brown 
31967cd05799SMatthew G. Knepley /*@
3197eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
31987cd05799SMatthew G. Knepley 
3199a1cb98faSBarry Smith   Not Collective
32007cd05799SMatthew G. Knepley 
32017cd05799SMatthew G. Knepley   Input Parameters:
3202a1cb98faSBarry Smith + mesh - The `DMPLEX`
3203a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
32047cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
32057cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
32067cd05799SMatthew G. Knepley 
32077cd05799SMatthew G. Knepley   Level: beginner
32087cd05799SMatthew G. Knepley 
32091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
32107cd05799SMatthew G. Knepley @*/
3211d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3212d71ae5a4SJacob Faibussowitsch {
3213552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3214552f7358SJed Brown   PetscInt pStart, pEnd;
3215552f7358SJed Brown   PetscInt dof, off;
3216552f7358SJed Brown 
3217552f7358SJed Brown   PetscFunctionBegin;
3218552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3219a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
32209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
322163a3b9bcSJacob Faibussowitsch     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);
322263a3b9bcSJacob Faibussowitsch     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);
32239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
322463a3b9bcSJacob Faibussowitsch     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);
3225a03d55ffSStefano Zampini   }
3226a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3227552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
32283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3229552f7358SJed Brown }
3230552f7358SJed Brown 
32317cd05799SMatthew G. Knepley /*@
3232eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
32337cd05799SMatthew G. Knepley 
3234a1cb98faSBarry Smith   Not Collective
32357cd05799SMatthew G. Knepley 
32367cd05799SMatthew G. Knepley   Input Parameters:
3237a1cb98faSBarry Smith + mesh - The `DMPLEX`
3238a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
32397cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
32407cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
32417cd05799SMatthew G. Knepley 
32427cd05799SMatthew G. Knepley   Level: beginner
32437cd05799SMatthew G. Knepley 
3244a1cb98faSBarry Smith   Note:
3245a1cb98faSBarry Smith   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3246b5a892a1SMatthew G. Knepley 
32471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
32487cd05799SMatthew G. Knepley @*/
3249d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3250d71ae5a4SJacob Faibussowitsch {
325177c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
325277c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
325377c88f5bSMatthew G Knepley   PetscInt dof, off;
325477c88f5bSMatthew G Knepley 
325577c88f5bSMatthew G Knepley   PetscFunctionBegin;
325677c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3257a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
32589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
325963a3b9bcSJacob Faibussowitsch     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);
32609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
326163a3b9bcSJacob Faibussowitsch     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);
3262a03d55ffSStefano Zampini   }
3263a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
326477c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
32653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
326677c88f5bSMatthew G Knepley }
326777c88f5bSMatthew G Knepley 
32689f4ada15SMatthew G. Knepley /*@C
32699f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
32709f4ada15SMatthew G. Knepley 
32719f4ada15SMatthew G. Knepley   Not collective
32729f4ada15SMatthew G. Knepley 
32739f4ada15SMatthew G. Knepley   Input Parameters:
32749f4ada15SMatthew G. Knepley + dm - The DMPlex
32759f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
32769f4ada15SMatthew G. Knepley 
32779f4ada15SMatthew G. Knepley   Output Parameters:
327820f4b53cSBarry Smith + cone - An array of points which are on the in-edges for point `p`
327920f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
32809f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
32819f4ada15SMatthew G. Knepley 
32829f4ada15SMatthew G. Knepley   Level: beginner
32839f4ada15SMatthew G. Knepley 
32849f4ada15SMatthew G. Knepley   Notes:
32859f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
32869f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
328720f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
32889f4ada15SMatthew G. Knepley   with the identity.
32899f4ada15SMatthew G. Knepley 
32909f4ada15SMatthew G. Knepley   Fortran Notes:
329120f4b53cSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
329220f4b53cSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
32939f4ada15SMatthew G. Knepley 
32941cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
32959f4ada15SMatthew G. Knepley @*/
32969f4ada15SMatthew G. Knepley PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
32979f4ada15SMatthew G. Knepley {
32989f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
32999f4ada15SMatthew G. Knepley 
33009f4ada15SMatthew G. Knepley   PetscFunctionBegin;
33019f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33029f4ada15SMatthew G. Knepley   if (mesh->tr) {
33039f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
33049f4ada15SMatthew G. Knepley   } else {
33059f4ada15SMatthew G. Knepley     PetscInt off;
33069f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
33079f4ada15SMatthew G. Knepley       PetscInt dof;
33089f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
33099f4ada15SMatthew G. Knepley       if (dof) {
33109f4ada15SMatthew G. Knepley         if (cone) PetscValidPointer(cone, 3);
33119f4ada15SMatthew G. Knepley         if (ornt) PetscValidPointer(ornt, 4);
33129f4ada15SMatthew G. Knepley       }
33139f4ada15SMatthew G. Knepley     }
33149f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
33159f4ada15SMatthew G. Knepley     if (cone) *cone = &mesh->cones[off];
33169f4ada15SMatthew G. Knepley     if (ornt) *ornt = &mesh->coneOrientations[off];
33179f4ada15SMatthew G. Knepley   }
33183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33199f4ada15SMatthew G. Knepley }
33209f4ada15SMatthew G. Knepley 
33219f4ada15SMatthew G. Knepley /*@C
33229f4ada15SMatthew G. Knepley   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG
33239f4ada15SMatthew G. Knepley 
332420f4b53cSBarry Smith   Not Collective
33259f4ada15SMatthew G. Knepley 
33269f4ada15SMatthew G. Knepley   Input Parameters:
33279f4ada15SMatthew G. Knepley + dm - The DMPlex
332820f4b53cSBarry Smith . p  - The point, which must lie in the chart set with `DMPlexSetChart()`
33299f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
333020f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
33319f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
33329f4ada15SMatthew G. Knepley 
33339f4ada15SMatthew G. Knepley   Level: beginner
33349f4ada15SMatthew G. Knepley 
33359f4ada15SMatthew G. Knepley   Notes:
33369f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
33379f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
333820f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
33399f4ada15SMatthew G. Knepley   with the identity.
33409f4ada15SMatthew G. Knepley 
334120f4b53cSBarry Smith   Fortran Note:
334220f4b53cSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
334320f4b53cSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
33449f4ada15SMatthew G. Knepley 
33451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
33469f4ada15SMatthew G. Knepley @*/
33479f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
33489f4ada15SMatthew G. Knepley {
33499f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
33509f4ada15SMatthew G. Knepley 
33519f4ada15SMatthew G. Knepley   PetscFunctionBegin;
33529f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33539f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
33543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33559f4ada15SMatthew G. Knepley }
33569f4ada15SMatthew G. Knepley 
3357552f7358SJed Brown /*@
3358eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3359552f7358SJed Brown 
3360a1cb98faSBarry Smith   Not Collective
3361552f7358SJed Brown 
3362552f7358SJed Brown   Input Parameters:
3363a1cb98faSBarry Smith + mesh - The `DMPLEX`
3364a1cb98faSBarry Smith - p - The point, which must lie in the chart set with `DMPlexSetChart()`
3365552f7358SJed Brown 
3366552f7358SJed Brown   Output Parameter:
336720f4b53cSBarry Smith . size - The support size for point `p`
3368552f7358SJed Brown 
3369552f7358SJed Brown   Level: beginner
3370552f7358SJed Brown 
33711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3372552f7358SJed Brown @*/
3373d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3374d71ae5a4SJacob Faibussowitsch {
3375552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3376552f7358SJed Brown 
3377552f7358SJed Brown   PetscFunctionBegin;
3378552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3379dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
33809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
33813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3382552f7358SJed Brown }
3383552f7358SJed Brown 
3384552f7358SJed Brown /*@
3385eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3386552f7358SJed Brown 
3387a1cb98faSBarry Smith   Not Collective
3388552f7358SJed Brown 
3389552f7358SJed Brown   Input Parameters:
3390a1cb98faSBarry Smith + mesh - The `DMPLEX`
3391a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
339220f4b53cSBarry Smith - size - The support size for point `p`
3393552f7358SJed Brown 
3394a1cb98faSBarry Smith   Level: beginner
3395552f7358SJed Brown 
3396552f7358SJed Brown   Note:
339720f4b53cSBarry Smith   This should be called after `DMPlexSetChart()`.
3398552f7358SJed Brown 
33991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3400552f7358SJed Brown @*/
3401d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3402d71ae5a4SJacob Faibussowitsch {
3403552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3404552f7358SJed Brown 
3405552f7358SJed Brown   PetscFunctionBegin;
3406552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
34083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3409552f7358SJed Brown }
3410552f7358SJed Brown 
3411552f7358SJed Brown /*@C
3412eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3413552f7358SJed Brown 
3414a1cb98faSBarry Smith   Not Collective
3415552f7358SJed Brown 
3416552f7358SJed Brown   Input Parameters:
3417a1cb98faSBarry Smith + mesh - The `DMPLEX`
3418a1cb98faSBarry Smith - p - The point, which must lie in the chart set with `DMPlexSetChart()`
3419552f7358SJed Brown 
3420552f7358SJed Brown   Output Parameter:
342120f4b53cSBarry Smith . support - An array of points which are on the out-edges for point `p`
3422552f7358SJed Brown 
3423552f7358SJed Brown   Level: beginner
3424552f7358SJed Brown 
3425a1cb98faSBarry Smith   Fortran Note:
3426a1cb98faSBarry Smith   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3427a1cb98faSBarry Smith   `DMPlexRestoreSupport()` is not needed/available in C.
34283813dfbdSMatthew G Knepley 
34291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3430552f7358SJed Brown @*/
3431d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3432d71ae5a4SJacob Faibussowitsch {
3433552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3434552f7358SJed Brown   PetscInt off;
3435552f7358SJed Brown 
3436552f7358SJed Brown   PetscFunctionBegin;
3437552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3438552f7358SJed Brown   PetscValidPointer(support, 3);
34399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3440552f7358SJed Brown   *support = &mesh->supports[off];
34413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3442552f7358SJed Brown }
3443552f7358SJed Brown 
3444552f7358SJed Brown /*@
344592371b87SBarry Smith   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3446552f7358SJed Brown 
3447a1cb98faSBarry Smith   Not Collective
3448552f7358SJed Brown 
3449552f7358SJed Brown   Input Parameters:
3450a1cb98faSBarry Smith + mesh - The `DMPLEX`
3451a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
345220f4b53cSBarry Smith - support - An array of points which are on the out-edges for point `p`
3453552f7358SJed Brown 
3454552f7358SJed Brown   Level: beginner
3455552f7358SJed Brown 
3456a1cb98faSBarry Smith   Note:
3457a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3458a1cb98faSBarry Smith 
34591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3460552f7358SJed Brown @*/
3461d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3462d71ae5a4SJacob Faibussowitsch {
3463552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3464552f7358SJed Brown   PetscInt pStart, pEnd;
3465552f7358SJed Brown   PetscInt dof, off, c;
3466552f7358SJed Brown 
3467552f7358SJed Brown   PetscFunctionBegin;
3468552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
34709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3471dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(support, 3);
34729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
347363a3b9bcSJacob Faibussowitsch   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);
3474552f7358SJed Brown   for (c = 0; c < dof; ++c) {
347563a3b9bcSJacob Faibussowitsch     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);
3476552f7358SJed Brown     mesh->supports[off + c] = support[c];
3477552f7358SJed Brown   }
34783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3479552f7358SJed Brown }
3480552f7358SJed Brown 
34817cd05799SMatthew G. Knepley /*@
3482eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
34837cd05799SMatthew G. Knepley 
3484a1cb98faSBarry Smith   Not Collective
34857cd05799SMatthew G. Knepley 
34867cd05799SMatthew G. Knepley   Input Parameters:
3487a1cb98faSBarry Smith + mesh - The `DMPLEX`
3488a1cb98faSBarry Smith . p - The point, which must lie in the chart set with `DMPlexSetChart()`
34897cd05799SMatthew G. Knepley . supportPos - The local index in the cone where the point should be put
34907cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
34917cd05799SMatthew G. Knepley 
34927cd05799SMatthew G. Knepley   Level: beginner
34937cd05799SMatthew G. Knepley 
34941cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
34957cd05799SMatthew G. Knepley @*/
3496d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3497d71ae5a4SJacob Faibussowitsch {
3498552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3499552f7358SJed Brown   PetscInt pStart, pEnd;
3500552f7358SJed Brown   PetscInt dof, off;
3501552f7358SJed Brown 
3502552f7358SJed Brown   PetscFunctionBegin;
3503552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
35059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
35069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
350763a3b9bcSJacob Faibussowitsch   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);
350863a3b9bcSJacob Faibussowitsch   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);
350963a3b9bcSJacob Faibussowitsch   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);
3510552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
35113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3512552f7358SJed Brown }
3513552f7358SJed Brown 
3514b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3515d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3516d71ae5a4SJacob Faibussowitsch {
3517b5a892a1SMatthew G. Knepley   switch (ct) {
3518b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3519b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3520b5a892a1SMatthew G. Knepley     break;
3521b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3522b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3523b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3524b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3525b5a892a1SMatthew G. Knepley     break;
3526b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3527b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3528b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3529b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3530b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3531b5a892a1SMatthew G. Knepley     break;
3532d71ae5a4SJacob Faibussowitsch   default:
3533d71ae5a4SJacob Faibussowitsch     return o;
3534b5a892a1SMatthew G. Knepley   }
3535b5a892a1SMatthew G. Knepley   return o;
3536b5a892a1SMatthew G. Knepley }
3537b5a892a1SMatthew G. Knepley 
3538b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3539d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3540d71ae5a4SJacob Faibussowitsch {
3541b5a892a1SMatthew G. Knepley   switch (ct) {
3542b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3543b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3544b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3545b5a892a1SMatthew G. Knepley     break;
3546b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3547b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3548b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3549b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3550b5a892a1SMatthew G. Knepley     break;
3551b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3552b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3553b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3554b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3555b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3556b5a892a1SMatthew G. Knepley     break;
3557d71ae5a4SJacob Faibussowitsch   default:
3558d71ae5a4SJacob Faibussowitsch     return o;
3559b5a892a1SMatthew G. Knepley   }
3560b5a892a1SMatthew G. Knepley   return o;
3561b5a892a1SMatthew G. Knepley }
3562b5a892a1SMatthew G. Knepley 
3563b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3564d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3565d71ae5a4SJacob Faibussowitsch {
3566b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3567b5a892a1SMatthew G. Knepley 
3568b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
35699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3570b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3571b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3572b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3573b5a892a1SMatthew G. Knepley 
35749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
35759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
35769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3577b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3578b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3579b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3580b5a892a1SMatthew G. Knepley 
35819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3582b5a892a1SMatthew G. Knepley       switch (ct) {
3583b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
35849566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
35859566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3586b5a892a1SMatthew G. Knepley         break;
3587b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
35889566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
35899566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
35909566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3591b5a892a1SMatthew G. Knepley         break;
3592b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
35939566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
35949566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
35959566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
35969566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3597b5a892a1SMatthew G. Knepley         break;
3598d71ae5a4SJacob Faibussowitsch       default:
3599d71ae5a4SJacob Faibussowitsch         break;
3600b5a892a1SMatthew G. Knepley       }
3601b5a892a1SMatthew G. Knepley     }
3602b5a892a1SMatthew G. Knepley   }
36033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3604b5a892a1SMatthew G. Knepley }
3605b5a892a1SMatthew G. Knepley 
360609015e70SStefano Zampini static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
360709015e70SStefano Zampini {
360809015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
360909015e70SStefano Zampini 
361009015e70SStefano Zampini   PetscFunctionBeginHot;
361109015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
361209015e70SStefano Zampini     if (useCone) {
361309015e70SStefano Zampini       PetscCall(DMPlexGetConeSize(dm, p, size));
361409015e70SStefano Zampini       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
361509015e70SStefano Zampini     } else {
361609015e70SStefano Zampini       PetscCall(DMPlexGetSupportSize(dm, p, size));
361709015e70SStefano Zampini       PetscCall(DMPlexGetSupport(dm, p, arr));
361809015e70SStefano Zampini     }
361909015e70SStefano Zampini   } else {
362009015e70SStefano Zampini     if (useCone) {
362109015e70SStefano Zampini       const PetscSection s   = mesh->coneSection;
362209015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
362309015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
362409015e70SStefano Zampini 
362509015e70SStefano Zampini       *size = s->atlasDof[ps];
362609015e70SStefano Zampini       *arr  = mesh->cones + off;
362709015e70SStefano Zampini       *ornt = mesh->coneOrientations + off;
362809015e70SStefano Zampini     } else {
362909015e70SStefano Zampini       const PetscSection s   = mesh->supportSection;
363009015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
363109015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
363209015e70SStefano Zampini 
363309015e70SStefano Zampini       *size = s->atlasDof[ps];
363409015e70SStefano Zampini       *arr  = mesh->supports + off;
363509015e70SStefano Zampini     }
363609015e70SStefano Zampini   }
363709015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
363809015e70SStefano Zampini }
363909015e70SStefano Zampini 
364009015e70SStefano Zampini static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
364109015e70SStefano Zampini {
364209015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
364309015e70SStefano Zampini 
364409015e70SStefano Zampini   PetscFunctionBeginHot;
364509015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
364609015e70SStefano Zampini     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
364709015e70SStefano Zampini   }
364809015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
364909015e70SStefano Zampini }
365009015e70SStefano Zampini 
3651d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3652d71ae5a4SJacob Faibussowitsch {
3653b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3654b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3655b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3656b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3657b5a892a1SMatthew G. Knepley 
3658b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3659b5a892a1SMatthew G. Knepley   if (ornt) {
36609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3661b5a892a1SMatthew G. Knepley     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3662b5a892a1SMatthew G. Knepley   }
3663b5a892a1SMatthew G. Knepley   if (*points) {
3664b5a892a1SMatthew G. Knepley     closure = *points;
3665b5a892a1SMatthew G. Knepley   } else {
3666b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
36679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
36689566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3669b5a892a1SMatthew G. Knepley   }
367009015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3671b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3672b5a892a1SMatthew G. Knepley     closure[off++] = p;
3673b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3674b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3675b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3676b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3677b5a892a1SMatthew G. Knepley     }
3678b5a892a1SMatthew G. Knepley   } else {
36795f80ce2aSJacob Faibussowitsch     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3680b5a892a1SMatthew G. Knepley 
3681b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3682b5a892a1SMatthew G. Knepley     closure[off++] = p;
3683b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3684b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3685b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3686b5a892a1SMatthew G. Knepley 
36879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3688b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3689b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3690b5a892a1SMatthew G. Knepley     }
3691b5a892a1SMatthew G. Knepley   }
369209015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3693b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
3694b5a892a1SMatthew G. Knepley   if (points) *points = closure;
36953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3696b5a892a1SMatthew G. Knepley }
3697b5a892a1SMatthew G. Knepley 
3698d5b43468SJose E. Roman /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3699d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3700d71ae5a4SJacob Faibussowitsch {
3701b5a892a1SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3702b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3703b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
3704b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3705b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3706b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3707b5a892a1SMatthew G. Knepley 
3708b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
37099566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
371009015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
37119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3712b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3713b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3714b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
37159371c9d4SSatish Balay   if (*points) {
37169371c9d4SSatish Balay     pts = *points;
37179371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3718b5a892a1SMatthew G. Knepley   c        = 0;
3719b5a892a1SMatthew G. Knepley   pts[c++] = point;
3720b5a892a1SMatthew G. Knepley   pts[c++] = o;
37219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
37229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
37239371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
37249371c9d4SSatish Balay     pts[c++] = closure[cl];
37259371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
37269371c9d4SSatish Balay   }
37279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
37289371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
37299371c9d4SSatish Balay     pts[c++] = closure[cl];
37309371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
37319371c9d4SSatish Balay   }
37329566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3733b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
37349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3735b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
3736b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3737b5a892a1SMatthew G. Knepley   }
373809015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3739b5a892a1SMatthew G. Knepley   if (dim >= 3) {
3740b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
3741b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3742b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
3743b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
3744b5a892a1SMatthew G. Knepley 
37459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3746b5a892a1SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
374709015e70SStefano Zampini       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3748b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
3749b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3750b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
3751b5a892a1SMatthew G. Knepley 
37529371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
37539371c9d4SSatish Balay           if (pts[i] == cp) break;
3754b5a892a1SMatthew G. Knepley         if (i == c) {
37559566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3756b5a892a1SMatthew G. Knepley           pts[c++] = cp;
3757b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3758b5a892a1SMatthew G. Knepley         }
3759b5a892a1SMatthew G. Knepley       }
376009015e70SStefano Zampini       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3761b5a892a1SMatthew G. Knepley     }
3762b5a892a1SMatthew G. Knepley   }
3763b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
3764b5a892a1SMatthew G. Knepley   *points    = pts;
37653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3766b5a892a1SMatthew G. Knepley }
3767b5a892a1SMatthew G. Knepley 
3768d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3769d71ae5a4SJacob Faibussowitsch {
3770b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
3771b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
3772b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3773b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3774b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
3775b5a892a1SMatthew G. Knepley 
3776b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
37779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
3778b5a892a1SMatthew G. Knepley   if (depth == 1) {
37799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
37803ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3781b5a892a1SMatthew G. Knepley   }
37829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
3783b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3784b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
37859566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
37863ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3787b5a892a1SMatthew G. Knepley   }
37889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3789b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3790b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3791b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
37929566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
37939371c9d4SSatish Balay   if (*points) {
37949371c9d4SSatish Balay     closure = *points;
37959371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
3796b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
3797b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
3798b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
3799b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
3800b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
3801b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3802b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
3803b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
3804b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
3805b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
3806b5a892a1SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
380709015e70SStefano Zampini     const PetscInt      *tmp, *tmpO = NULL;
3808b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
3809b5a892a1SMatthew G. Knepley 
3810b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
3811b5a892a1SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2;
381263a3b9bcSJacob Faibussowitsch       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);
3813b5a892a1SMatthew G. Knepley     }
381409015e70SStefano Zampini     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3815b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3816b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
3817b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
3818b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
38199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
3820b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3821b5a892a1SMatthew G. Knepley       PetscInt       c;
3822b5a892a1SMatthew G. Knepley 
3823b5a892a1SMatthew G. Knepley       /* Check for duplicate */
3824b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
3825b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
3826b5a892a1SMatthew G. Knepley       }
3827b5a892a1SMatthew G. Knepley       if (c == closureSize) {
3828b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
3829b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
3830b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
3831b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
3832b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
3833b5a892a1SMatthew G. Knepley       }
3834b5a892a1SMatthew G. Knepley     }
383509015e70SStefano Zampini     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3836b5a892a1SMatthew G. Knepley   }
38379566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3838b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
3839b5a892a1SMatthew G. Knepley   if (points) *points = closure;
38403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3841b5a892a1SMatthew G. Knepley }
3842b5a892a1SMatthew G. Knepley 
3843552f7358SJed Brown /*@C
3844eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3845552f7358SJed Brown 
3846a1cb98faSBarry Smith   Not Collective
3847552f7358SJed Brown 
3848552f7358SJed Brown   Input Parameters:
3849a1cb98faSBarry Smith + dm      - The `DMPLEX`
3850b5a892a1SMatthew G. Knepley . p       - The mesh point
3851a1cb98faSBarry Smith - useCone - `PETSC_TRUE` for the closure, otherwise return the star
3852552f7358SJed Brown 
38536b867d5aSJose E. Roman   Input/Output Parameter:
38546b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
385520f4b53cSBarry Smith            if `NULL` on input, internal storage will be returned, otherwise the provided array is used
38566b867d5aSJose E. Roman 
38576b867d5aSJose E. Roman   Output Parameter:
385820f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
3859552f7358SJed Brown 
3860a1cb98faSBarry Smith   Level: beginner
3861a1cb98faSBarry Smith 
3862552f7358SJed Brown   Note:
386320f4b53cSBarry Smith   If using internal storage (points is `NULL` on input), each call overwrites the last output.
3864552f7358SJed Brown 
38659f22da38SBarry Smith   Fortran Note:
386620f4b53cSBarry Smith   The `numPoints` argument is not present in the Fortran binding since it is internal to the array.
38673813dfbdSMatthew G Knepley 
38681cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3869552f7358SJed Brown @*/
3870d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3871d71ae5a4SJacob Faibussowitsch {
3872b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3873552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3874b5a892a1SMatthew G. Knepley   if (numPoints) PetscValidIntPointer(numPoints, 4);
3875b5a892a1SMatthew G. Knepley   if (points) PetscValidPointer(points, 5);
38769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
38773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38789bf0dad6SMatthew G. Knepley }
38799bf0dad6SMatthew G. Knepley 
3880552f7358SJed Brown /*@C
3881eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3882552f7358SJed Brown 
3883a1cb98faSBarry Smith   Not Collective
3884552f7358SJed Brown 
3885552f7358SJed Brown   Input Parameters:
3886a1cb98faSBarry Smith + dm        - The `DMPLEX`
3887b5a892a1SMatthew G. Knepley . p         - The mesh point
3888a1cb98faSBarry Smith . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
388920f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
3890b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3891552f7358SJed Brown 
3892a1cb98faSBarry Smith   Level: beginner
3893a1cb98faSBarry Smith 
3894552f7358SJed Brown   Note:
389520f4b53cSBarry Smith   If not using internal storage (points is not `NULL` on input), this call is unnecessary
3896552f7358SJed Brown 
38971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3898552f7358SJed Brown @*/
3899d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3900d71ae5a4SJacob Faibussowitsch {
3901b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3902552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
39034ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
39049566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
39053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3906552f7358SJed Brown }
3907552f7358SJed Brown 
3908552f7358SJed Brown /*@
3909eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3910552f7358SJed Brown 
3911a1cb98faSBarry Smith   Not Collective
3912552f7358SJed Brown 
3913552f7358SJed Brown   Input Parameter:
3914a1cb98faSBarry Smith . mesh - The `DMPLEX`
3915552f7358SJed Brown 
3916552f7358SJed Brown   Output Parameters:
3917552f7358SJed Brown + maxConeSize - The maximum number of in-edges
3918552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
3919552f7358SJed Brown 
3920552f7358SJed Brown   Level: beginner
3921552f7358SJed Brown 
39221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3923552f7358SJed Brown @*/
3924d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3925d71ae5a4SJacob Faibussowitsch {
3926552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3927552f7358SJed Brown 
3928552f7358SJed Brown   PetscFunctionBegin;
3929552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
39301baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
39311baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
39323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3933552f7358SJed Brown }
3934552f7358SJed Brown 
3935d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
3936d71ae5a4SJacob Faibussowitsch {
3937552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
39386302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
3939552f7358SJed Brown 
3940552f7358SJed Brown   PetscFunctionBegin;
3941552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
39429566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
39439566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
39449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
39459566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
39466302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
39476302a7fbSVaclav Hapla   if (maxSupportSize) {
39489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
39499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
39509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
3951552f7358SJed Brown   }
39523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3953552f7358SJed Brown }
3954552f7358SJed Brown 
3955d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3956d71ae5a4SJacob Faibussowitsch {
3957552f7358SJed Brown   PetscFunctionBegin;
39589566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
39599566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3960ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
3961736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
396295602cf2SAlexis Marboeuf     PetscSF sfNatural;
3963f94b4a02SBlaise Bourdin 
39643dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
39659566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
396695602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
3967c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
3968f94b4a02SBlaise Bourdin   }
39693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3970552f7358SJed Brown }
3971552f7358SJed Brown 
3972d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3973d71ae5a4SJacob Faibussowitsch {
39743dcd263cSBlaise Bourdin   PetscInt i = 0;
39752adcc780SMatthew G. Knepley 
39762adcc780SMatthew G. Knepley   PetscFunctionBegin;
39779566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
39789566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
3979c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
39803dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
39813dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
398295602cf2SAlexis Marboeuf       PetscSF sfNatural;
39833dcd263cSBlaise Bourdin 
39843dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
39859566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
3986c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
398795602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
3988c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
39893dcd263cSBlaise Bourdin       break;
39903dcd263cSBlaise Bourdin     }
39913dcd263cSBlaise Bourdin   }
39923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39932adcc780SMatthew G. Knepley }
39942adcc780SMatthew G. Knepley 
3995552f7358SJed Brown /*@
3996eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3997552f7358SJed Brown 
3998a1cb98faSBarry Smith   Not Collective
3999552f7358SJed Brown 
4000552f7358SJed Brown   Input Parameter:
4001a1cb98faSBarry Smith . mesh - The `DMPLEX`
4002552f7358SJed Brown 
4003552f7358SJed Brown   Level: beginner
4004552f7358SJed Brown 
4005a1cb98faSBarry Smith   Note:
4006a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetCone()`
4007a1cb98faSBarry Smith 
40081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4009552f7358SJed Brown @*/
4010d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
4011d71ae5a4SJacob Faibussowitsch {
4012552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4013552f7358SJed Brown   PetscInt *offsets;
4014552f7358SJed Brown   PetscInt  supportSize;
4015552f7358SJed Brown   PetscInt  pStart, pEnd, p;
4016552f7358SJed Brown 
4017552f7358SJed Brown   PetscFunctionBegin;
4018552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
401928b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
40209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4021552f7358SJed Brown   /* Calculate support sizes */
40229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4023552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4024552f7358SJed Brown     PetscInt dof, off, c;
4025552f7358SJed Brown 
40269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
40279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
402848a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4029552f7358SJed Brown   }
40309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
4031552f7358SJed Brown   /* Calculate supports */
40329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
40339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
40349566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4035552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4036552f7358SJed Brown     PetscInt dof, off, c;
4037552f7358SJed Brown 
40389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
40399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4040552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
4041552f7358SJed Brown       const PetscInt q = mesh->cones[c];
4042552f7358SJed Brown       PetscInt       offS;
4043552f7358SJed Brown 
40449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
40450d644c17SKarl Rupp 
4046552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
4047552f7358SJed Brown       ++offsets[q];
4048552f7358SJed Brown     }
4049552f7358SJed Brown   }
40509566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
40519566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
40523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4053552f7358SJed Brown }
4054552f7358SJed Brown 
4055d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4056d71ae5a4SJacob Faibussowitsch {
4057277ea44aSLisandro Dalcin   IS stratumIS;
4058277ea44aSLisandro Dalcin 
4059277ea44aSLisandro Dalcin   PetscFunctionBegin;
40603ba16761SJacob Faibussowitsch   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
406176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4062277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4063277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
40649566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4065277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
40669566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
40679371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
40689371c9d4SSatish Balay         overlap = PETSC_TRUE;
40699371c9d4SSatish Balay         break;
40709371c9d4SSatish Balay       }
4071277ea44aSLisandro Dalcin     }
407263a3b9bcSJacob Faibussowitsch     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);
4073277ea44aSLisandro Dalcin   }
40749566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
40759566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
40769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
40773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4078277ea44aSLisandro Dalcin }
4079277ea44aSLisandro Dalcin 
4080552f7358SJed Brown /*@
4081a8d69d7bSBarry Smith   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
40826dd80730SBarry Smith   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
4083552f7358SJed Brown   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
4084552f7358SJed Brown   the DAG.
4085552f7358SJed Brown 
408620f4b53cSBarry Smith   Collective
4087552f7358SJed Brown 
4088552f7358SJed Brown   Input Parameter:
4089a1cb98faSBarry Smith . mesh - The `DMPLEX`
4090552f7358SJed Brown 
4091a1cb98faSBarry Smith   Level: beginner
4092552f7358SJed Brown 
4093552f7358SJed Brown   Notes:
4094a1cb98faSBarry Smith   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4095b1bb481bSMatthew Knepley   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
4096a1cb98faSBarry Smith   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4097a1cb98faSBarry Smith   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4098a1cb98faSBarry Smith   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4099552f7358SJed Brown 
4100b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4101b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4102b1bb481bSMatthew Knepley   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
4103b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4104a1cb98faSBarry Smith .vb
4105a1cb98faSBarry Smith   cone(c0) = {e0, v2}
4106a1cb98faSBarry Smith   cone(e0) = {v0, v1}
4107a1cb98faSBarry Smith .ve
4108a1cb98faSBarry Smith   If `DMPlexStratify()` is run on this mesh, it will give depths
4109a1cb98faSBarry Smith .vb
4110a1cb98faSBarry Smith    depth 0 = {v0, v1, v2}
4111a1cb98faSBarry Smith    depth 1 = {e0, c0}
4112a1cb98faSBarry Smith .ve
4113b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4114b1bb481bSMatthew Knepley 
4115a1cb98faSBarry Smith   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4116552f7358SJed Brown 
41171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4118552f7358SJed Brown @*/
4119d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4120d71ae5a4SJacob Faibussowitsch {
4121df0420ecSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
4122aa50250dSMatthew G. Knepley   DMLabel  label;
4123552f7358SJed Brown   PetscInt pStart, pEnd, p;
4124552f7358SJed Brown   PetscInt numRoots = 0, numLeaves = 0;
4125552f7358SJed Brown 
4126552f7358SJed Brown   PetscFunctionBegin;
4127552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4129277ea44aSLisandro Dalcin 
4130277ea44aSLisandro Dalcin   /* Create depth label */
41319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
41329566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
41339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4134277ea44aSLisandro Dalcin 
4135277ea44aSLisandro Dalcin   {
4136552f7358SJed Brown     /* Initialize roots and count leaves */
4137277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
4138277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
4139552f7358SJed Brown     PetscInt coneSize, supportSize;
4140552f7358SJed Brown 
4141277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
41429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
41439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4144552f7358SJed Brown       if (!coneSize && supportSize) {
4145277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
4146277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
4147552f7358SJed Brown         ++numRoots;
4148552f7358SJed Brown       } else if (!supportSize && coneSize) {
4149552f7358SJed Brown         ++numLeaves;
4150552f7358SJed Brown       } else if (!supportSize && !coneSize) {
4151552f7358SJed Brown         /* Isolated points */
4152277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
4153277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
4154552f7358SJed Brown       }
4155552f7358SJed Brown     }
41569566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4157277ea44aSLisandro Dalcin   }
4158277ea44aSLisandro Dalcin 
4159552f7358SJed Brown   if (numRoots + numLeaves == (pEnd - pStart)) {
4160277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
4161277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
4162552f7358SJed Brown     PetscInt coneSize, supportSize;
4163552f7358SJed Brown 
4164277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
41659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
41669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4167552f7358SJed Brown       if (!supportSize && coneSize) {
4168277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
4169277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
4170552f7358SJed Brown       }
4171552f7358SJed Brown     }
41729566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4173552f7358SJed Brown   } else {
4174277ea44aSLisandro Dalcin     PetscInt level = 0;
4175277ea44aSLisandro Dalcin     PetscInt qStart, qEnd, q;
4176552f7358SJed Brown 
41779566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4178277ea44aSLisandro Dalcin     while (qEnd > qStart) {
4179277ea44aSLisandro Dalcin       PetscInt sMin = PETSC_MAX_INT;
4180277ea44aSLisandro Dalcin       PetscInt sMax = PETSC_MIN_INT;
418174ef644bSMatthew G. Knepley 
4182277ea44aSLisandro Dalcin       for (q = qStart; q < qEnd; ++q) {
418374ef644bSMatthew G. Knepley         const PetscInt *support;
418474ef644bSMatthew G. Knepley         PetscInt        supportSize, s;
418574ef644bSMatthew G. Knepley 
41869566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
41879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, q, &support));
418874ef644bSMatthew G. Knepley         for (s = 0; s < supportSize; ++s) {
4189277ea44aSLisandro Dalcin           sMin = PetscMin(support[s], sMin);
4190277ea44aSLisandro Dalcin           sMax = PetscMax(support[s], sMax);
4191552f7358SJed Brown         }
4192552f7358SJed Brown       }
41939566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &level));
41949566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
41959566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
419674ef644bSMatthew G. Knepley     }
419774ef644bSMatthew G. Knepley   }
4198bf4602e4SToby Isaac   { /* just in case there is an empty process */
4199bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4200bf4602e4SToby Isaac 
42019566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
4202712fec58SPierre Jolivet     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
420348a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4204bf4602e4SToby Isaac   }
42059566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
42069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
42073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4208552f7358SJed Brown }
4209552f7358SJed Brown 
4210d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4211d71ae5a4SJacob Faibussowitsch {
4212412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4213412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4214ba2698f1SMatthew G. Knepley 
4215412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
42169566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
42179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
42189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4219ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4220ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4221ba2698f1SMatthew G. Knepley     switch (pdepth) {
4222d71ae5a4SJacob Faibussowitsch     case 0:
4223d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4224d71ae5a4SJacob Faibussowitsch       break;
4225ba2698f1SMatthew G. Knepley     case 1:
4226ba2698f1SMatthew G. Knepley       switch (coneSize) {
4227d71ae5a4SJacob Faibussowitsch       case 2:
4228d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4229d71ae5a4SJacob Faibussowitsch         break;
4230d71ae5a4SJacob Faibussowitsch       case 3:
4231d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4232d71ae5a4SJacob Faibussowitsch         break;
4233ba2698f1SMatthew G. Knepley       case 4:
4234ba2698f1SMatthew G. Knepley         switch (dim) {
4235d71ae5a4SJacob Faibussowitsch         case 2:
4236d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4237d71ae5a4SJacob Faibussowitsch           break;
4238d71ae5a4SJacob Faibussowitsch         case 3:
4239d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4240d71ae5a4SJacob Faibussowitsch           break;
4241d71ae5a4SJacob Faibussowitsch         default:
4242d71ae5a4SJacob Faibussowitsch           break;
4243ba2698f1SMatthew G. Knepley         }
4244ba2698f1SMatthew G. Knepley         break;
4245d71ae5a4SJacob Faibussowitsch       case 5:
4246d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4247d71ae5a4SJacob Faibussowitsch         break;
4248d71ae5a4SJacob Faibussowitsch       case 6:
4249d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4250d71ae5a4SJacob Faibussowitsch         break;
4251d71ae5a4SJacob Faibussowitsch       case 8:
4252d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4253d71ae5a4SJacob Faibussowitsch         break;
4254d71ae5a4SJacob Faibussowitsch       default:
4255d71ae5a4SJacob Faibussowitsch         break;
4256ba2698f1SMatthew G. Knepley       }
4257ba2698f1SMatthew G. Knepley     }
4258ba2698f1SMatthew G. Knepley   } else {
4259ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4260ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4261ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4262ba2698f1SMatthew G. Knepley       switch (dim) {
4263ba2698f1SMatthew G. Knepley       case 1:
4264ba2698f1SMatthew G. Knepley         switch (coneSize) {
4265d71ae5a4SJacob Faibussowitsch         case 2:
4266d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4267d71ae5a4SJacob Faibussowitsch           break;
4268d71ae5a4SJacob Faibussowitsch         default:
4269d71ae5a4SJacob Faibussowitsch           break;
4270ba2698f1SMatthew G. Knepley         }
4271ba2698f1SMatthew G. Knepley         break;
4272ba2698f1SMatthew G. Knepley       case 2:
4273ba2698f1SMatthew G. Knepley         switch (coneSize) {
4274d71ae5a4SJacob Faibussowitsch         case 3:
4275d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4276d71ae5a4SJacob Faibussowitsch           break;
4277d71ae5a4SJacob Faibussowitsch         case 4:
4278d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4279d71ae5a4SJacob Faibussowitsch           break;
4280d71ae5a4SJacob Faibussowitsch         default:
4281d71ae5a4SJacob Faibussowitsch           break;
4282ba2698f1SMatthew G. Knepley         }
4283ba2698f1SMatthew G. Knepley         break;
4284ba2698f1SMatthew G. Knepley       case 3:
4285ba2698f1SMatthew G. Knepley         switch (coneSize) {
4286d71ae5a4SJacob Faibussowitsch         case 4:
4287d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4288d71ae5a4SJacob Faibussowitsch           break;
42899371c9d4SSatish Balay         case 5: {
4290da9060c4SMatthew G. Knepley           const PetscInt *cone;
4291da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4292da9060c4SMatthew G. Knepley 
42939566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
42949566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4295da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4296d71ae5a4SJacob Faibussowitsch           case 3:
4297d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4298d71ae5a4SJacob Faibussowitsch             break;
4299d71ae5a4SJacob Faibussowitsch           case 4:
4300d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4301d71ae5a4SJacob Faibussowitsch             break;
4302da9060c4SMatthew G. Knepley           }
43039371c9d4SSatish Balay         } break;
4304d71ae5a4SJacob Faibussowitsch         case 6:
4305d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4306d71ae5a4SJacob Faibussowitsch           break;
4307d71ae5a4SJacob Faibussowitsch         default:
4308d71ae5a4SJacob Faibussowitsch           break;
4309ba2698f1SMatthew G. Knepley         }
4310ba2698f1SMatthew G. Knepley         break;
4311d71ae5a4SJacob Faibussowitsch       default:
4312d71ae5a4SJacob Faibussowitsch         break;
4313ba2698f1SMatthew G. Knepley       }
4314ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4315ba2698f1SMatthew G. Knepley       switch (coneSize) {
4316d71ae5a4SJacob Faibussowitsch       case 2:
4317d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4318d71ae5a4SJacob Faibussowitsch         break;
4319d71ae5a4SJacob Faibussowitsch       case 3:
4320d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4321d71ae5a4SJacob Faibussowitsch         break;
4322d71ae5a4SJacob Faibussowitsch       case 4:
4323d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4324d71ae5a4SJacob Faibussowitsch         break;
4325d71ae5a4SJacob Faibussowitsch       default:
4326d71ae5a4SJacob Faibussowitsch         break;
4327ba2698f1SMatthew G. Knepley       }
4328ba2698f1SMatthew G. Knepley     }
4329ba2698f1SMatthew G. Knepley   }
4330412e9a14SMatthew G. Knepley   *pt = ct;
43313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4332ba2698f1SMatthew G. Knepley }
4333412e9a14SMatthew G. Knepley 
4334412e9a14SMatthew G. Knepley /*@
4335412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4336412e9a14SMatthew G. Knepley 
433720f4b53cSBarry Smith   Collective
4338412e9a14SMatthew G. Knepley 
4339412e9a14SMatthew G. Knepley   Input Parameter:
4340a1cb98faSBarry Smith . mesh - The `DMPLEX`
4341412e9a14SMatthew G. Knepley 
4342412e9a14SMatthew G. Knepley   Level: developer
4343412e9a14SMatthew G. Knepley 
4344a1cb98faSBarry Smith   Note:
4345a1cb98faSBarry Smith   This function is normally called automatically when a cell type is requested. It creates an
4346a1cb98faSBarry Smith   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4347a1cb98faSBarry Smith   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4348412e9a14SMatthew G. Knepley 
4349a1cb98faSBarry Smith   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4350a1cb98faSBarry Smith 
43511cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4352412e9a14SMatthew G. Knepley @*/
4353d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4354d71ae5a4SJacob Faibussowitsch {
4355412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4356412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4357412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4358412e9a14SMatthew G. Knepley 
4359412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4360412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4361412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
43629566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
43639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
43649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
436521027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
436621027e53SStefano Zampini   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4367412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4368327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4369412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4370412e9a14SMatthew G. Knepley 
43719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
43729566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
437363a3b9bcSJacob Faibussowitsch     PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p);
43749566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
437521027e53SStefano Zampini     mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4376412e9a14SMatthew G. Knepley   }
43779566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
43789566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
43793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4380ba2698f1SMatthew G. Knepley }
4381ba2698f1SMatthew G. Knepley 
4382552f7358SJed Brown /*@C
4383552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4384552f7358SJed Brown 
4385552f7358SJed Brown   Not Collective
4386552f7358SJed Brown 
4387552f7358SJed Brown   Input Parameters:
4388a1cb98faSBarry Smith + dm - The `DMPLEX` object
4389552f7358SJed Brown . numPoints - The number of input points for the join
4390552f7358SJed Brown - points - The input points
4391552f7358SJed Brown 
4392552f7358SJed Brown   Output Parameters:
4393552f7358SJed Brown + numCoveredPoints - The number of points in the join
4394552f7358SJed Brown - coveredPoints - The points in the join
4395552f7358SJed Brown 
4396552f7358SJed Brown   Level: intermediate
4397552f7358SJed Brown 
4398a1cb98faSBarry Smith   Note:
4399a1cb98faSBarry Smith   Currently, this is restricted to a single level join
4400552f7358SJed Brown 
4401a1cb98faSBarry Smith   Fortran Note:
440220f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
44033813dfbdSMatthew G Knepley 
44041cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4405552f7358SJed Brown @*/
4406d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4407d71ae5a4SJacob Faibussowitsch {
4408552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4409552f7358SJed Brown   PetscInt *join[2];
4410552f7358SJed Brown   PetscInt  joinSize, i = 0;
4411552f7358SJed Brown   PetscInt  dof, off, p, c, m;
44126302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4413552f7358SJed Brown 
4414552f7358SJed Brown   PetscFunctionBegin;
4415552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
441648bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
441748bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
441848bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
44196302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
44206302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
44216302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4422552f7358SJed Brown   /* Copy in support of first point */
44239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
44249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4425ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4426552f7358SJed Brown   /* Check each successive support */
4427552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4428552f7358SJed Brown     PetscInt newJoinSize = 0;
4429552f7358SJed Brown 
44309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
44319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4432552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4433552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4434552f7358SJed Brown 
4435552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4436552f7358SJed Brown         if (point == join[i][m]) {
4437552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4438552f7358SJed Brown           break;
4439552f7358SJed Brown         }
4440552f7358SJed Brown       }
4441552f7358SJed Brown     }
4442552f7358SJed Brown     joinSize = newJoinSize;
4443552f7358SJed Brown     i        = 1 - i;
4444552f7358SJed Brown   }
4445552f7358SJed Brown   *numCoveredPoints = joinSize;
4446552f7358SJed Brown   *coveredPoints    = join[i];
44476302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
44483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4449552f7358SJed Brown }
4450552f7358SJed Brown 
4451552f7358SJed Brown /*@C
4452552f7358SJed Brown   DMPlexRestoreJoin - Restore an array for the join of the set of points
4453552f7358SJed Brown 
4454552f7358SJed Brown   Not Collective
4455552f7358SJed Brown 
4456552f7358SJed Brown   Input Parameters:
4457a1cb98faSBarry Smith + dm - The `DMPLEX` object
4458552f7358SJed Brown . numPoints - The number of input points for the join
4459552f7358SJed Brown - points - The input points
4460552f7358SJed Brown 
4461552f7358SJed Brown   Output Parameters:
4462552f7358SJed Brown + numCoveredPoints - The number of points in the join
4463552f7358SJed Brown - coveredPoints - The points in the join
4464552f7358SJed Brown 
4465552f7358SJed Brown   Level: intermediate
4466552f7358SJed Brown 
4467a1cb98faSBarry Smith   Fortran Note:
446820f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4469a1cb98faSBarry Smith 
44701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4471552f7358SJed Brown @*/
4472d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4473d71ae5a4SJacob Faibussowitsch {
4474552f7358SJed Brown   PetscFunctionBegin;
4475552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4476d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points, 3);
4477d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4);
4478d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints, 5);
44799566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4480d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
44813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4482552f7358SJed Brown }
4483552f7358SJed Brown 
4484552f7358SJed Brown /*@C
4485552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4486552f7358SJed Brown 
4487552f7358SJed Brown   Not Collective
4488552f7358SJed Brown 
4489552f7358SJed Brown   Input Parameters:
4490a1cb98faSBarry Smith + dm - The `DMPLEX` object
4491552f7358SJed Brown . numPoints - The number of input points for the join
4492552f7358SJed Brown - points - The input points
4493552f7358SJed Brown 
4494552f7358SJed Brown   Output Parameters:
4495552f7358SJed Brown + numCoveredPoints - The number of points in the join
4496552f7358SJed Brown - coveredPoints - The points in the join
4497552f7358SJed Brown 
4498552f7358SJed Brown   Level: intermediate
4499552f7358SJed Brown 
4500a1cb98faSBarry Smith   Fortran Note:
450120f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4502a1cb98faSBarry Smith 
45031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4504552f7358SJed Brown @*/
4505d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4506d71ae5a4SJacob Faibussowitsch {
4507552f7358SJed Brown   PetscInt *offsets, **closures;
4508552f7358SJed Brown   PetscInt *join[2];
4509552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
451024c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4511552f7358SJed Brown 
4512552f7358SJed Brown   PetscFunctionBegin;
4513552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
451448bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
451548bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
451648bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
4517552f7358SJed Brown 
45189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
45199566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
45209566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
45216302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
452224c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
45239566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
45249566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4525552f7358SJed Brown 
4526552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4527552f7358SJed Brown     PetscInt closureSize;
4528552f7358SJed Brown 
45299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
45300d644c17SKarl Rupp 
4531552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4532552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4533552f7358SJed Brown       PetscInt pStart, pEnd, i;
4534552f7358SJed Brown 
45359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4536552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4537552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4538552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4539552f7358SJed Brown           break;
4540552f7358SJed Brown         }
4541552f7358SJed Brown       }
4542552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4543552f7358SJed Brown     }
454463a3b9bcSJacob Faibussowitsch     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);
4545552f7358SJed Brown   }
4546552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4547552f7358SJed Brown     PetscInt dof;
4548552f7358SJed Brown 
4549552f7358SJed Brown     /* Copy in support of first point */
4550552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4551ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4552552f7358SJed Brown     /* Check each successive cone */
4553552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4554552f7358SJed Brown       PetscInt newJoinSize = 0;
4555552f7358SJed Brown 
4556552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
4557552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4558552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
4559552f7358SJed Brown 
4560552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4561552f7358SJed Brown           if (point == join[i][m]) {
4562552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
4563552f7358SJed Brown             break;
4564552f7358SJed Brown           }
4565552f7358SJed Brown         }
4566552f7358SJed Brown       }
4567552f7358SJed Brown       joinSize = newJoinSize;
4568552f7358SJed Brown       i        = 1 - i;
4569552f7358SJed Brown     }
4570552f7358SJed Brown     if (joinSize) break;
4571552f7358SJed Brown   }
4572552f7358SJed Brown   *numCoveredPoints = joinSize;
4573552f7358SJed Brown   *coveredPoints    = join[i];
457448a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
45759566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
45769566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
45776302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
45783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4579552f7358SJed Brown }
4580552f7358SJed Brown 
4581552f7358SJed Brown /*@C
4582552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4583552f7358SJed Brown 
4584552f7358SJed Brown   Not Collective
4585552f7358SJed Brown 
4586552f7358SJed Brown   Input Parameters:
4587a1cb98faSBarry Smith + dm - The `DMPLEX` object
4588552f7358SJed Brown . numPoints - The number of input points for the meet
4589552f7358SJed Brown - points - The input points
4590552f7358SJed Brown 
4591552f7358SJed Brown   Output Parameters:
4592552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4593552f7358SJed Brown - coveredPoints - The points in the meet
4594552f7358SJed Brown 
4595552f7358SJed Brown   Level: intermediate
4596552f7358SJed Brown 
4597a1cb98faSBarry Smith   Note:
4598a1cb98faSBarry Smith   Currently, this is restricted to a single level meet
4599552f7358SJed Brown 
46003813dfbdSMatthew G Knepley   Fortran Notes:
460120f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
46023813dfbdSMatthew G Knepley 
46031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4604552f7358SJed Brown @*/
4605d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4606d71ae5a4SJacob Faibussowitsch {
4607552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4608552f7358SJed Brown   PetscInt *meet[2];
4609552f7358SJed Brown   PetscInt  meetSize, i = 0;
4610552f7358SJed Brown   PetscInt  dof, off, p, c, m;
46116302a7fbSVaclav Hapla   PetscInt  maxConeSize;
4612552f7358SJed Brown 
4613552f7358SJed Brown   PetscFunctionBegin;
4614552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4615dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4616dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveringPoints, 4);
4617064a246eSJacob Faibussowitsch   PetscValidPointer(coveringPoints, 5);
46186302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
46196302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
46206302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4621552f7358SJed Brown   /* Copy in cone of first point */
46229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
46239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4624ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4625552f7358SJed Brown   /* Check each successive cone */
4626552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4627552f7358SJed Brown     PetscInt newMeetSize = 0;
4628552f7358SJed Brown 
46299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
46309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4631552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4632552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
4633552f7358SJed Brown 
4634552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
4635552f7358SJed Brown         if (point == meet[i][m]) {
4636552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
4637552f7358SJed Brown           break;
4638552f7358SJed Brown         }
4639552f7358SJed Brown       }
4640552f7358SJed Brown     }
4641552f7358SJed Brown     meetSize = newMeetSize;
4642552f7358SJed Brown     i        = 1 - i;
4643552f7358SJed Brown   }
4644552f7358SJed Brown   *numCoveringPoints = meetSize;
4645552f7358SJed Brown   *coveringPoints    = meet[i];
46466302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
46473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4648552f7358SJed Brown }
4649552f7358SJed Brown 
4650552f7358SJed Brown /*@C
4651552f7358SJed Brown   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4652552f7358SJed Brown 
4653552f7358SJed Brown   Not Collective
4654552f7358SJed Brown 
4655552f7358SJed Brown   Input Parameters:
4656a1cb98faSBarry Smith + dm - The `DMPLEX` object
4657552f7358SJed Brown . numPoints - The number of input points for the meet
4658552f7358SJed Brown - points - The input points
4659552f7358SJed Brown 
4660552f7358SJed Brown   Output Parameters:
4661552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4662552f7358SJed Brown - coveredPoints - The points in the meet
4663552f7358SJed Brown 
4664552f7358SJed Brown   Level: intermediate
4665552f7358SJed Brown 
4666a1cb98faSBarry Smith   Fortran Note:
466720f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
46683813dfbdSMatthew G Knepley 
46691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4670552f7358SJed Brown @*/
4671d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4672d71ae5a4SJacob Faibussowitsch {
4673552f7358SJed Brown   PetscFunctionBegin;
4674552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4675d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points, 3);
4676d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4);
4677d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints, 5);
46789566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4679d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
46803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4681552f7358SJed Brown }
4682552f7358SJed Brown 
4683552f7358SJed Brown /*@C
4684552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
4685552f7358SJed Brown 
4686552f7358SJed Brown   Not Collective
4687552f7358SJed Brown 
4688552f7358SJed Brown   Input Parameters:
4689a1cb98faSBarry Smith + dm - The `DMPLEX` object
4690552f7358SJed Brown . numPoints - The number of input points for the meet
4691552f7358SJed Brown - points - The input points
4692552f7358SJed Brown 
4693552f7358SJed Brown   Output Parameters:
4694552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4695552f7358SJed Brown - coveredPoints - The points in the meet
4696552f7358SJed Brown 
4697552f7358SJed Brown   Level: intermediate
4698552f7358SJed Brown 
4699a1cb98faSBarry Smith   Fortran Note:
470020f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
47013813dfbdSMatthew G Knepley 
47021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4703552f7358SJed Brown @*/
4704d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4705d71ae5a4SJacob Faibussowitsch {
4706552f7358SJed Brown   PetscInt *offsets, **closures;
4707552f7358SJed Brown   PetscInt *meet[2];
4708552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
470924c766afSToby Isaac   PetscInt  p, h, c, m, mc;
4710552f7358SJed Brown 
4711552f7358SJed Brown   PetscFunctionBegin;
4712552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4713dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4714dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveredPoints, 4);
4715064a246eSJacob Faibussowitsch   PetscValidPointer(coveredPoints, 5);
4716552f7358SJed Brown 
47179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
47189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
47199566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
47206302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
472124c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
47229566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
47239566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4724552f7358SJed Brown 
4725552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4726552f7358SJed Brown     PetscInt closureSize;
4727552f7358SJed Brown 
47289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
47290d644c17SKarl Rupp 
4730552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
4731552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
4732552f7358SJed Brown       PetscInt pStart, pEnd, i;
4733552f7358SJed Brown 
47349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4735552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
4736552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4737552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
4738552f7358SJed Brown           break;
4739552f7358SJed Brown         }
4740552f7358SJed Brown       }
4741552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
4742552f7358SJed Brown     }
474363a3b9bcSJacob Faibussowitsch     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);
4744552f7358SJed Brown   }
4745552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
4746552f7358SJed Brown     PetscInt dof;
4747552f7358SJed Brown 
4748552f7358SJed Brown     /* Copy in cone of first point */
4749552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
4750ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
4751552f7358SJed Brown     /* Check each successive cone */
4752552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
4753552f7358SJed Brown       PetscInt newMeetSize = 0;
4754552f7358SJed Brown 
4755552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
4756552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4757552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
4758552f7358SJed Brown 
4759552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
4760552f7358SJed Brown           if (point == meet[i][m]) {
4761552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
4762552f7358SJed Brown             break;
4763552f7358SJed Brown           }
4764552f7358SJed Brown         }
4765552f7358SJed Brown       }
4766552f7358SJed Brown       meetSize = newMeetSize;
4767552f7358SJed Brown       i        = 1 - i;
4768552f7358SJed Brown     }
4769552f7358SJed Brown     if (meetSize) break;
4770552f7358SJed Brown   }
4771552f7358SJed Brown   *numCoveredPoints = meetSize;
4772552f7358SJed Brown   *coveredPoints    = meet[i];
477348a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
47749566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
47759566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
47766302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
47773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4778552f7358SJed Brown }
4779552f7358SJed Brown 
47804e3744c5SMatthew G. Knepley /*@C
4781a1cb98faSBarry Smith   DMPlexEqual - Determine if two `DM` have the same topology
47824e3744c5SMatthew G. Knepley 
47834e3744c5SMatthew G. Knepley   Not Collective
47844e3744c5SMatthew G. Knepley 
47854e3744c5SMatthew G. Knepley   Input Parameters:
4786a1cb98faSBarry Smith + dmA - A `DMPLEX` object
4787a1cb98faSBarry Smith - dmB - A `DMPLEX` object
47884e3744c5SMatthew G. Knepley 
47892fe279fdSBarry Smith   Output Parameter:
4790a1cb98faSBarry Smith . equal - `PETSC_TRUE` if the topologies are identical
47914e3744c5SMatthew G. Knepley 
47924e3744c5SMatthew G. Knepley   Level: intermediate
47934e3744c5SMatthew G. Knepley 
4794a1cb98faSBarry Smith   Note:
47953c7db156SBarry Smith   We are not solving graph isomorphism, so we do not permute.
47964e3744c5SMatthew G. Knepley 
47971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
47984e3744c5SMatthew G. Knepley @*/
4799d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4800d71ae5a4SJacob Faibussowitsch {
48014e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
48024e3744c5SMatthew G. Knepley 
48034e3744c5SMatthew G. Knepley   PetscFunctionBegin;
48044e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
48054e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4806dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(equal, 3);
48074e3744c5SMatthew G. Knepley 
48084e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
48099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
48109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
48113ba16761SJacob Faibussowitsch   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
48129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
48139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
48143ba16761SJacob Faibussowitsch   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
48154e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
48164e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
48174e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
48184e3744c5SMatthew G. Knepley 
48199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
48209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
48219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
48229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
48239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
48249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
48253ba16761SJacob Faibussowitsch     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
48264e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
48273ba16761SJacob Faibussowitsch       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
48283ba16761SJacob Faibussowitsch       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
48294e3744c5SMatthew G. Knepley     }
48309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
48319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
48329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
48339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
48343ba16761SJacob Faibussowitsch     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
48354e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
48363ba16761SJacob Faibussowitsch       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
48374e3744c5SMatthew G. Knepley     }
48384e3744c5SMatthew G. Knepley   }
48394e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
48403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48414e3744c5SMatthew G. Knepley }
48424e3744c5SMatthew G. Knepley 
48437cd05799SMatthew G. Knepley /*@C
48447cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
48457cd05799SMatthew G. Knepley 
48467cd05799SMatthew G. Knepley   Not Collective
48477cd05799SMatthew G. Knepley 
48487cd05799SMatthew G. Knepley   Input Parameters:
4849a1cb98faSBarry Smith + dm         - The `DMPLEX`
48507cd05799SMatthew G. Knepley . cellDim    - The cell dimension
48517cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
48527cd05799SMatthew G. Knepley 
48532fe279fdSBarry Smith   Output Parameter:
48547cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
48557cd05799SMatthew G. Knepley 
48567cd05799SMatthew G. Knepley   Level: developer
48577cd05799SMatthew G. Knepley 
4858a1cb98faSBarry Smith   Note:
48597cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
48607cd05799SMatthew G. Knepley 
48611cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
48627cd05799SMatthew G. Knepley @*/
4863d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4864d71ae5a4SJacob Faibussowitsch {
486582f516ccSBarry Smith   MPI_Comm comm;
4866552f7358SJed Brown 
4867552f7358SJed Brown   PetscFunctionBegin;
48689566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4869dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numFaceVertices, 4);
4870552f7358SJed Brown   switch (cellDim) {
4871d71ae5a4SJacob Faibussowitsch   case 0:
4872d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
4873d71ae5a4SJacob Faibussowitsch     break;
4874d71ae5a4SJacob Faibussowitsch   case 1:
4875d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
4876d71ae5a4SJacob Faibussowitsch     break;
4877552f7358SJed Brown   case 2:
4878552f7358SJed Brown     switch (numCorners) {
487919436ca2SJed Brown     case 3:                 /* triangle */
488019436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4881552f7358SJed Brown       break;
488219436ca2SJed Brown     case 4:                 /* quadrilateral */
488319436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4884552f7358SJed Brown       break;
488519436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
488619436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4887552f7358SJed Brown       break;
488819436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
488919436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4890552f7358SJed Brown       break;
4891d71ae5a4SJacob Faibussowitsch     default:
4892d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4893552f7358SJed Brown     }
4894552f7358SJed Brown     break;
4895552f7358SJed Brown   case 3:
4896552f7358SJed Brown     switch (numCorners) {
489719436ca2SJed Brown     case 4:                 /* tetradehdron */
489819436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
4899552f7358SJed Brown       break;
490019436ca2SJed Brown     case 6:                 /* tet cohesive cells */
490119436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4902552f7358SJed Brown       break;
490319436ca2SJed Brown     case 8:                 /* hexahedron */
490419436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4905552f7358SJed Brown       break;
490619436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
490719436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4908552f7358SJed Brown       break;
490919436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
491019436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4911552f7358SJed Brown       break;
491219436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
491319436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4914552f7358SJed Brown       break;
491519436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
491619436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4917552f7358SJed Brown       break;
491819436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
491919436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
4920552f7358SJed Brown       break;
4921d71ae5a4SJacob Faibussowitsch     default:
4922d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4923552f7358SJed Brown     }
4924552f7358SJed Brown     break;
4925d71ae5a4SJacob Faibussowitsch   default:
4926d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
4927552f7358SJed Brown   }
49283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4929552f7358SJed Brown }
4930552f7358SJed Brown 
4931552f7358SJed Brown /*@
4932a1cb98faSBarry Smith   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
4933552f7358SJed Brown 
4934552f7358SJed Brown   Not Collective
4935552f7358SJed Brown 
4936aa50250dSMatthew G. Knepley   Input Parameter:
4937a1cb98faSBarry Smith . dm    - The `DMPLEX` object
4938552f7358SJed Brown 
4939aa50250dSMatthew G. Knepley   Output Parameter:
4940a1cb98faSBarry Smith . depthLabel - The `DMLabel` recording point depth
4941552f7358SJed Brown 
4942552f7358SJed Brown   Level: developer
4943552f7358SJed Brown 
49441cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
4945aa50250dSMatthew G. Knepley @*/
4946d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4947d71ae5a4SJacob Faibussowitsch {
4948aa50250dSMatthew G. Knepley   PetscFunctionBegin;
4949aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4950aa50250dSMatthew G. Knepley   PetscValidPointer(depthLabel, 2);
4951c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
49523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4953aa50250dSMatthew G. Knepley }
4954aa50250dSMatthew G. Knepley 
4955aa50250dSMatthew G. Knepley /*@
4956aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4957aa50250dSMatthew G. Knepley 
4958aa50250dSMatthew G. Knepley   Not Collective
4959aa50250dSMatthew G. Knepley 
4960aa50250dSMatthew G. Knepley   Input Parameter:
4961a1cb98faSBarry Smith . dm    - The `DMPLEX` object
4962aa50250dSMatthew G. Knepley 
4963aa50250dSMatthew G. Knepley   Output Parameter:
4964aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
4965aa50250dSMatthew G. Knepley 
4966aa50250dSMatthew G. Knepley   Level: developer
4967552f7358SJed Brown 
4968b1bb481bSMatthew Knepley   Notes:
4969a1cb98faSBarry Smith   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
4970a1cb98faSBarry Smith 
4971a1cb98faSBarry Smith   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
4972a1cb98faSBarry Smith 
4973dc287ab2SVaclav Hapla   An empty mesh gives -1.
4974b1bb481bSMatthew Knepley 
49751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
4976552f7358SJed Brown @*/
4977d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4978d71ae5a4SJacob Faibussowitsch {
49799f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
4980aa50250dSMatthew G. Knepley   DMLabel  label;
4981aa50250dSMatthew G. Knepley   PetscInt d = 0;
4982552f7358SJed Brown 
4983552f7358SJed Brown   PetscFunctionBegin;
4984552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4985dadcf809SJacob Faibussowitsch   PetscValidIntPointer(depth, 2);
49869f4ada15SMatthew G. Knepley   if (mesh->tr) {
49879f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
49889f4ada15SMatthew G. Knepley   } else {
49899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
49909566063dSJacob Faibussowitsch     if (label) PetscCall(DMLabelGetNumValues(label, &d));
4991552f7358SJed Brown     *depth = d - 1;
49929f4ada15SMatthew G. Knepley   }
49933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4994552f7358SJed Brown }
4995552f7358SJed Brown 
4996552f7358SJed Brown /*@
499720f4b53cSBarry Smith   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
4998552f7358SJed Brown 
4999552f7358SJed Brown   Not Collective
5000552f7358SJed Brown 
5001552f7358SJed Brown   Input Parameters:
5002a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5003570fa34dSVaclav Hapla - depth - The requested depth
5004552f7358SJed Brown 
5005552f7358SJed Brown   Output Parameters:
500620f4b53cSBarry Smith + start - The first point at this `depth`
500720f4b53cSBarry Smith - end   - One beyond the last point at this `depth`
5008552f7358SJed Brown 
5009552f7358SJed Brown   Level: developer
5010552f7358SJed Brown 
5011a1cb98faSBarry Smith   Notes:
5012a1cb98faSBarry Smith   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5013a1cb98faSBarry Smith   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5014a1cb98faSBarry Smith   higher dimension, e.g., "edges".
5015a1cb98faSBarry Smith 
50162827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5017552f7358SJed Brown @*/
5018d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5019d71ae5a4SJacob Faibussowitsch {
50209f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5021aa50250dSMatthew G. Knepley   DMLabel  label;
502263d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
5023552f7358SJed Brown 
5024552f7358SJed Brown   PetscFunctionBegin;
5025552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50269371c9d4SSatish Balay   if (start) {
50279371c9d4SSatish Balay     PetscValidIntPointer(start, 3);
50289371c9d4SSatish Balay     *start = 0;
50299371c9d4SSatish Balay   }
50309371c9d4SSatish Balay   if (end) {
50319371c9d4SSatish Balay     PetscValidIntPointer(end, 4);
50329371c9d4SSatish Balay     *end = 0;
50339371c9d4SSatish Balay   }
50349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
50353ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5036570fa34dSVaclav Hapla   if (depth < 0) {
503763d1a920SMatthew G. Knepley     if (start) *start = pStart;
503863d1a920SMatthew G. Knepley     if (end) *end = pEnd;
50393ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5040552f7358SJed Brown   }
50419f4ada15SMatthew G. Knepley   if (mesh->tr) {
50429f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
50439f4ada15SMatthew G. Knepley   } else {
50449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
504528b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5046570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
50479f4ada15SMatthew G. Knepley   }
50483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5049552f7358SJed Brown }
5050552f7358SJed Brown 
5051552f7358SJed Brown /*@
505220f4b53cSBarry Smith   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5053552f7358SJed Brown 
5054552f7358SJed Brown   Not Collective
5055552f7358SJed Brown 
5056552f7358SJed Brown   Input Parameters:
5057a1cb98faSBarry Smith + dm     - The `DMPLEX` object
5058570fa34dSVaclav Hapla - height - The requested height
5059552f7358SJed Brown 
5060552f7358SJed Brown   Output Parameters:
506120f4b53cSBarry Smith + start - The first point at this `height`
506220f4b53cSBarry Smith - end   - One beyond the last point at this `height`
5063552f7358SJed Brown 
5064552f7358SJed Brown   Level: developer
5065552f7358SJed Brown 
5066a1cb98faSBarry Smith   Notes:
5067a1cb98faSBarry Smith   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5068a1cb98faSBarry Smith   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5069a1cb98faSBarry Smith   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5070a1cb98faSBarry Smith 
50712827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5072552f7358SJed Brown @*/
5073d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5074d71ae5a4SJacob Faibussowitsch {
5075aa50250dSMatthew G. Knepley   DMLabel  label;
507663d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5077552f7358SJed Brown 
5078552f7358SJed Brown   PetscFunctionBegin;
5079552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50809371c9d4SSatish Balay   if (start) {
50819371c9d4SSatish Balay     PetscValidIntPointer(start, 3);
50829371c9d4SSatish Balay     *start = 0;
50839371c9d4SSatish Balay   }
50849371c9d4SSatish Balay   if (end) {
50859371c9d4SSatish Balay     PetscValidIntPointer(end, 4);
50869371c9d4SSatish Balay     *end = 0;
50879371c9d4SSatish Balay   }
50889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
50893ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5090570fa34dSVaclav Hapla   if (height < 0) {
509163d1a920SMatthew G. Knepley     if (start) *start = pStart;
509263d1a920SMatthew G. Knepley     if (end) *end = pEnd;
50933ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5094552f7358SJed Brown   }
50959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
5096*59e4dc13SStefano Zampini   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
5097*59e4dc13SStefano Zampini   else PetscCall(DMGetDimension(dm, &depth));
5098*59e4dc13SStefano Zampini   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
5099*59e4dc13SStefano Zampini   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
51003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5101552f7358SJed Brown }
5102552f7358SJed Brown 
5103ba2698f1SMatthew G. Knepley /*@
510420f4b53cSBarry Smith   DMPlexGetPointDepth - Get the `depth` of a given point
5105ba2698f1SMatthew G. Knepley 
5106ba2698f1SMatthew G. Knepley   Not Collective
5107ba2698f1SMatthew G. Knepley 
5108d8d19677SJose E. Roman   Input Parameters:
5109a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5110ba2698f1SMatthew G. Knepley - point - The point
5111ba2698f1SMatthew G. Knepley 
5112ba2698f1SMatthew G. Knepley   Output Parameter:
511320f4b53cSBarry Smith . depth - The depth of the `point`
5114ba2698f1SMatthew G. Knepley 
5115ba2698f1SMatthew G. Knepley   Level: intermediate
5116ba2698f1SMatthew G. Knepley 
51171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5118ba2698f1SMatthew G. Knepley @*/
5119d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5120d71ae5a4SJacob Faibussowitsch {
5121ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5122ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
512340a2aa30SMatthew G. Knepley   PetscValidIntPointer(depth, 3);
51249566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
51253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5126ba2698f1SMatthew G. Knepley }
5127ba2698f1SMatthew G. Knepley 
5128ba2698f1SMatthew G. Knepley /*@
512920f4b53cSBarry Smith   DMPlexGetPointHeight - Get the `height` of a given point
51300c0a32dcSVaclav Hapla 
51310c0a32dcSVaclav Hapla   Not Collective
51320c0a32dcSVaclav Hapla 
5133d8d19677SJose E. Roman   Input Parameters:
5134a1cb98faSBarry Smith + dm    - The `DMPLEX` object
51350c0a32dcSVaclav Hapla - point - The point
51360c0a32dcSVaclav Hapla 
51370c0a32dcSVaclav Hapla   Output Parameter:
513820f4b53cSBarry Smith . height - The height of the `point`
51390c0a32dcSVaclav Hapla 
51400c0a32dcSVaclav Hapla   Level: intermediate
51410c0a32dcSVaclav Hapla 
51421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
51430c0a32dcSVaclav Hapla @*/
5144d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5145d71ae5a4SJacob Faibussowitsch {
51460c0a32dcSVaclav Hapla   PetscInt n, pDepth;
51470c0a32dcSVaclav Hapla 
51480c0a32dcSVaclav Hapla   PetscFunctionBegin;
51490c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51500c0a32dcSVaclav Hapla   PetscValidIntPointer(height, 3);
51519566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
51529566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
51530c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
51543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51550c0a32dcSVaclav Hapla }
51560c0a32dcSVaclav Hapla 
51570c0a32dcSVaclav Hapla /*@
5158a1cb98faSBarry Smith   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5159ba2698f1SMatthew G. Knepley 
5160ba2698f1SMatthew G. Knepley   Not Collective
5161ba2698f1SMatthew G. Knepley 
5162ba2698f1SMatthew G. Knepley   Input Parameter:
5163a1cb98faSBarry Smith . dm - The `DMPLEX` object
5164ba2698f1SMatthew G. Knepley 
5165ba2698f1SMatthew G. Knepley   Output Parameter:
5166a1cb98faSBarry Smith . celltypeLabel - The `DMLabel` recording cell polytope type
5167412e9a14SMatthew G. Knepley 
5168ba2698f1SMatthew G. Knepley   Level: developer
5169ba2698f1SMatthew G. Knepley 
5170a1cb98faSBarry Smith   Note:
5171a1cb98faSBarry Smith   This function will trigger automatica computation of cell types. This can be disabled by calling
5172a1cb98faSBarry Smith   `DMCreateLabel`(dm, "celltype") beforehand.
5173a1cb98faSBarry Smith 
51741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5175ba2698f1SMatthew G. Knepley @*/
5176d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5177d71ae5a4SJacob Faibussowitsch {
5178ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5179ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5180ba2698f1SMatthew G. Knepley   PetscValidPointer(celltypeLabel, 2);
51819566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5182ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
51833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5184ba2698f1SMatthew G. Knepley }
5185ba2698f1SMatthew G. Knepley 
5186ba2698f1SMatthew G. Knepley /*@
5187ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5188ba2698f1SMatthew G. Knepley 
5189ba2698f1SMatthew G. Knepley   Not Collective
5190ba2698f1SMatthew G. Knepley 
5191d8d19677SJose E. Roman   Input Parameters:
5192a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5193ba2698f1SMatthew G. Knepley - cell - The cell
5194ba2698f1SMatthew G. Knepley 
5195ba2698f1SMatthew G. Knepley   Output Parameter:
5196ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5197ba2698f1SMatthew G. Knepley 
5198ba2698f1SMatthew G. Knepley   Level: intermediate
5199ba2698f1SMatthew G. Knepley 
52001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5201ba2698f1SMatthew G. Knepley @*/
5202d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5203d71ae5a4SJacob Faibussowitsch {
52049f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5205ba2698f1SMatthew G. Knepley   DMLabel  label;
5206ba2698f1SMatthew G. Knepley   PetscInt ct;
5207ba2698f1SMatthew G. Knepley 
5208ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5209ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5210ba2698f1SMatthew G. Knepley   PetscValidPointer(celltype, 3);
52119f4ada15SMatthew G. Knepley   if (mesh->tr) {
52129f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
52139f4ada15SMatthew G. Knepley   } else {
521421027e53SStefano Zampini     PetscInt pStart, pEnd;
521521027e53SStefano Zampini 
521621027e53SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
521721027e53SStefano Zampini     if (!mesh->cellTypes) { /* XXX remove? optimize? */
521821027e53SStefano Zampini       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
521921027e53SStefano Zampini       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
522021027e53SStefano Zampini       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
522121027e53SStefano Zampini       for (PetscInt p = pStart; p < pEnd; p++) {
522221027e53SStefano Zampini         PetscCall(DMLabelGetValue(label, p, &ct));
522321027e53SStefano Zampini         mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
522421027e53SStefano Zampini       }
522521027e53SStefano Zampini     }
522621027e53SStefano Zampini     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
522721027e53SStefano Zampini     if (PetscDefined(USE_DEBUG)) {
52289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
52299566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, cell, &ct));
523063a3b9bcSJacob Faibussowitsch       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
523121027e53SStefano Zampini       PetscCheck(ct == *celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
523221027e53SStefano Zampini     }
52339f4ada15SMatthew G. Knepley   }
52343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5235ba2698f1SMatthew G. Knepley }
5236ba2698f1SMatthew G. Knepley 
5237412e9a14SMatthew G. Knepley /*@
5238412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5239412e9a14SMatthew G. Knepley 
5240412e9a14SMatthew G. Knepley   Not Collective
5241412e9a14SMatthew G. Knepley 
5242412e9a14SMatthew G. Knepley   Input Parameters:
5243a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5244412e9a14SMatthew G. Knepley . cell - The cell
5245412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5246412e9a14SMatthew G. Knepley 
5247a1cb98faSBarry Smith   Level: advanced
5248a1cb98faSBarry Smith 
5249a1cb98faSBarry Smith   Note:
5250a1cb98faSBarry Smith   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5251412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5252412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5253db485b19SStefano Zampini   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5254412e9a14SMatthew G. Knepley 
52551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5256412e9a14SMatthew G. Knepley @*/
5257d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5258d71ae5a4SJacob Faibussowitsch {
525921027e53SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
5260412e9a14SMatthew G. Knepley   DMLabel  label;
526121027e53SStefano Zampini   PetscInt pStart, pEnd;
5262412e9a14SMatthew G. Knepley 
5263412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5264412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
526521027e53SStefano Zampini   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
52669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
52679566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
526821027e53SStefano Zampini   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
526921027e53SStefano Zampini   mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
52703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5271412e9a14SMatthew G. Knepley }
5272412e9a14SMatthew G. Knepley 
5273d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5274d71ae5a4SJacob Faibussowitsch {
5275efe440bfSMatthew G. Knepley   PetscSection section, s;
5276efe440bfSMatthew G. Knepley   Mat          m;
52773e922f36SToby Isaac   PetscInt     maxHeight;
5278dd4c3f67SMatthew G. Knepley   const char  *prefix;
5279552f7358SJed Brown 
5280552f7358SJed Brown   PetscFunctionBegin;
52819566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
5282dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5283dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5284dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
52859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
52869566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
52879566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
52889566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
52899566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
52909566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
52919566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
52929566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
52939566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&s));
52949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&m));
52958f4c458bSMatthew G. Knepley 
52969566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
52979566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5298dd4c3f67SMatthew G. Knepley   (*cdm)->cloneOpts = PETSC_TRUE;
5299dd4c3f67SMatthew G. Knepley   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
53003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5301552f7358SJed Brown }
5302552f7358SJed Brown 
5303d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5304d71ae5a4SJacob Faibussowitsch {
53056858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
53066858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5307f19dbd58SToby Isaac 
5308f19dbd58SToby Isaac   PetscFunctionBegin;
5309f19dbd58SToby Isaac   *field = NULL;
53109566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
53119566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
53126858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
53136858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5314f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
53156858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
53166858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5317f19dbd58SToby Isaac   }
53183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5319f19dbd58SToby Isaac }
5320f19dbd58SToby Isaac 
53217cd05799SMatthew G. Knepley /*@C
53227cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
53237cd05799SMatthew G. Knepley 
53247cd05799SMatthew G. Knepley   Not Collective
53257cd05799SMatthew G. Knepley 
53262fe279fdSBarry Smith   Input Parameter:
5327a1cb98faSBarry Smith . dm        - The `DMPLEX` object
53287cd05799SMatthew G. Knepley 
53297cd05799SMatthew G. Knepley   Output Parameter:
5330a1cb98faSBarry Smith . section - The `PetscSection` object
53317cd05799SMatthew G. Knepley 
53327cd05799SMatthew G. Knepley   Level: developer
53337cd05799SMatthew G. Knepley 
53341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
53357cd05799SMatthew G. Knepley @*/
5336d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5337d71ae5a4SJacob Faibussowitsch {
5338552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5339552f7358SJed Brown 
5340552f7358SJed Brown   PetscFunctionBegin;
5341552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5342552f7358SJed Brown   if (section) *section = mesh->coneSection;
53433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5344552f7358SJed Brown }
5345552f7358SJed Brown 
53467cd05799SMatthew G. Knepley /*@C
53477cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
53487cd05799SMatthew G. Knepley 
53497cd05799SMatthew G. Knepley   Not Collective
53507cd05799SMatthew G. Knepley 
53512fe279fdSBarry Smith   Input Parameter:
5352a1cb98faSBarry Smith . dm        - The `DMPLEX` object
53537cd05799SMatthew G. Knepley 
53547cd05799SMatthew G. Knepley   Output Parameter:
5355a1cb98faSBarry Smith . section - The `PetscSection` object
53567cd05799SMatthew G. Knepley 
53577cd05799SMatthew G. Knepley   Level: developer
53587cd05799SMatthew G. Knepley 
53591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
53607cd05799SMatthew G. Knepley @*/
5361d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5362d71ae5a4SJacob Faibussowitsch {
53638cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
53648cb4d582SMatthew G. Knepley 
53658cb4d582SMatthew G. Knepley   PetscFunctionBegin;
53668cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53678cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
53683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
53698cb4d582SMatthew G. Knepley }
53708cb4d582SMatthew G. Knepley 
53717cd05799SMatthew G. Knepley /*@C
53727cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
53737cd05799SMatthew G. Knepley 
53747cd05799SMatthew G. Knepley   Not Collective
53757cd05799SMatthew G. Knepley 
53762fe279fdSBarry Smith   Input Parameter:
5377a1cb98faSBarry Smith . dm        - The `DMPLEX` object
53787cd05799SMatthew G. Knepley 
53797cd05799SMatthew G. Knepley   Output Parameter:
53807cd05799SMatthew G. Knepley . cones - The cone for each point
53817cd05799SMatthew G. Knepley 
53827cd05799SMatthew G. Knepley   Level: developer
53837cd05799SMatthew G. Knepley 
53841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
53857cd05799SMatthew G. Knepley @*/
5386d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5387d71ae5a4SJacob Faibussowitsch {
5388552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5389552f7358SJed Brown 
5390552f7358SJed Brown   PetscFunctionBegin;
5391552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5392552f7358SJed Brown   if (cones) *cones = mesh->cones;
53933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5394552f7358SJed Brown }
5395552f7358SJed Brown 
53967cd05799SMatthew G. Knepley /*@C
53977cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
53987cd05799SMatthew G. Knepley 
53997cd05799SMatthew G. Knepley   Not Collective
54007cd05799SMatthew G. Knepley 
54012fe279fdSBarry Smith   Input Parameter:
5402a1cb98faSBarry Smith . dm        - The `DMPLEX` object
54037cd05799SMatthew G. Knepley 
54047cd05799SMatthew G. Knepley   Output Parameter:
5405b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
54067cd05799SMatthew G. Knepley 
54077cd05799SMatthew G. Knepley   Level: developer
54087cd05799SMatthew G. Knepley 
5409b5a892a1SMatthew G. Knepley   Notes:
5410a1cb98faSBarry Smith   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`.
5411b5a892a1SMatthew G. Knepley 
5412a1cb98faSBarry Smith   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5413b5a892a1SMatthew G. Knepley 
54141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
54157cd05799SMatthew G. Knepley @*/
5416d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5417d71ae5a4SJacob Faibussowitsch {
5418552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5419552f7358SJed Brown 
5420552f7358SJed Brown   PetscFunctionBegin;
5421552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5422552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
54233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5424552f7358SJed Brown }
5425552f7358SJed Brown 
5426552f7358SJed Brown /******************************** FEM Support **********************************/
5427552f7358SJed Brown 
54289e8305c2SJed Brown /*
54299e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
54309e8305c2SJed Brown  representing a line in the section.
54319e8305c2SJed Brown */
5432d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k)
5433d71ae5a4SJacob Faibussowitsch {
54349e8305c2SJed Brown   PetscFunctionBeginHot;
54359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5436a433471fSStefano Zampini   if (line < 0) {
5437a433471fSStefano Zampini     *k  = 0;
5438a433471fSStefano Zampini     *Nc = 0;
5439a433471fSStefano Zampini   } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */
54409e8305c2SJed Brown     *k = 1;
54419e8305c2SJed Brown   } else { /* Assume the full interpolated mesh is in the chart; lines in particular */
54429e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
54439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
54449e8305c2SJed Brown     *k = *k / *Nc + 1;
54459e8305c2SJed Brown   }
54463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54479e8305c2SJed Brown }
54489e8305c2SJed Brown 
5449a4355906SMatthew Knepley /*@
5450bc1eb3faSJed Brown 
5451bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5452bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
545320f4b53cSBarry Smith   section provided (or the section of the `DM`).
5454a4355906SMatthew Knepley 
5455a4355906SMatthew Knepley   Input Parameters:
545620f4b53cSBarry Smith + dm      - The `DM`
545720f4b53cSBarry Smith . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
545820f4b53cSBarry Smith - section - The `PetscSection` to reorder, or `NULL` for the default section
5459a4355906SMatthew Knepley 
5460bc1eb3faSJed Brown   Example:
5461bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5462bc1eb3faSJed Brown .vb
5463bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5464bc1eb3faSJed Brown 
5465bc1eb3faSJed Brown   v4 -- e6 -- v3
5466bc1eb3faSJed Brown   |           |
5467bc1eb3faSJed Brown   e7    c0    e8
5468bc1eb3faSJed Brown   |           |
5469bc1eb3faSJed Brown   v1 -- e5 -- v2
5470bc1eb3faSJed Brown .ve
5471bc1eb3faSJed Brown 
5472bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5473bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5474bc1eb3faSJed Brown .vb
5475bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5476bc1eb3faSJed Brown     v1 -> [4]
5477bc1eb3faSJed Brown     ...
5478bc1eb3faSJed Brown     e5 -> [8, 9]
5479bc1eb3faSJed Brown .ve
5480bc1eb3faSJed Brown 
5481bc1eb3faSJed Brown   which corresponds to the dofs
5482bc1eb3faSJed Brown .vb
5483bc1eb3faSJed Brown     6   10  11  7
5484bc1eb3faSJed Brown     13  2   3   15
5485bc1eb3faSJed Brown     12  0   1   14
5486bc1eb3faSJed Brown     4   8   9   5
5487bc1eb3faSJed Brown .ve
5488bc1eb3faSJed Brown 
5489bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5490bc1eb3faSJed Brown .vb
5491bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5492bc1eb3faSJed Brown .ve
5493bc1eb3faSJed Brown 
5494bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5495bc1eb3faSJed Brown .vb
5496bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5497bc1eb3faSJed Brown .ve
5498bc1eb3faSJed Brown 
5499a4355906SMatthew Knepley   Level: developer
5500a4355906SMatthew Knepley 
5501a1cb98faSBarry Smith   Note:
5502a1cb98faSBarry Smith   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5503a1cb98faSBarry Smith   degree of the basis.
5504a1cb98faSBarry Smith 
55051cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5506a4355906SMatthew Knepley @*/
5507d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5508d71ae5a4SJacob Faibussowitsch {
55097391a63aSMatthew G. Knepley   DMLabel   label;
5510bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
55119e8305c2SJed Brown   PetscBool vertexchart;
55123194fc30SMatthew G. Knepley 
55133194fc30SMatthew G. Knepley   PetscFunctionBegin;
55149566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
55153ba16761SJacob Faibussowitsch   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5516a433471fSStefano Zampini   if (point < 0) {
5517a433471fSStefano Zampini     PetscInt sStart, sEnd;
5518a433471fSStefano Zampini 
55199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5520a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
5521a433471fSStefano Zampini   }
55229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
55239566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
55249566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
55259371c9d4SSatish Balay   if (depth == 1) {
55269371c9d4SSatish Balay     eStart = point;
55279371c9d4SSatish Balay   } else if (depth == dim) {
55287391a63aSMatthew G. Knepley     const PetscInt *cone;
55297391a63aSMatthew G. Knepley 
55309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5531d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5532d4e6627bSStefano Zampini     else if (dim == 3) {
5533d4e6627bSStefano Zampini       const PetscInt *cone2;
55349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5535d4e6627bSStefano Zampini       eStart = cone2[0];
553663a3b9bcSJacob Faibussowitsch     } 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);
553763a3b9bcSJacob Faibussowitsch   } 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);
55389e8305c2SJed Brown   { /* Determine whether the chart covers all points or just vertices. */
55399e8305c2SJed Brown     PetscInt pStart, pEnd, cStart, cEnd;
55409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd));
55419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section, &cStart, &cEnd));
5542796d0a68SJed Brown     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5543796d0a68SJed Brown     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5544796d0a68SJed Brown     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
55459e8305c2SJed Brown   }
55469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5547bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
5548bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5549bb197d40SJed Brown     PetscInt *perm;
5550bb197d40SJed Brown 
55513194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
55529566063dSJacob Faibussowitsch       PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5553bb197d40SJed Brown       size += PetscPowInt(k + 1, d) * Nc;
55543194fc30SMatthew G. Knepley     }
55559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
55563194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5557bb197d40SJed Brown       switch (d) {
5558babf31e0SJed Brown       case 1:
55599566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5560babf31e0SJed Brown         /*
5561babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5562babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5563babf31e0SJed Brown          */
5564babf31e0SJed Brown         for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
55659371c9d4SSatish Balay         for (i = 0; i < k - 1; i++)
55669371c9d4SSatish Balay           for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5567babf31e0SJed Brown         for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5568babf31e0SJed Brown         foffset = offset;
5569babf31e0SJed Brown         break;
557089eabcffSMatthew G. Knepley       case 2:
55713194fc30SMatthew G. Knepley         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
55729566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
55733194fc30SMatthew G. Knepley         /* The SEM order is
55743194fc30SMatthew G. Knepley 
55753194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
557689eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
55773194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
55783194fc30SMatthew G. Knepley          */
55793194fc30SMatthew G. Knepley         {
55803194fc30SMatthew G. Knepley           const PetscInt of   = 0;
55813194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
55823194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
55833194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
55843194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
55853194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
55863194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
55873194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
55883194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
55893194fc30SMatthew G. Knepley           PetscInt       o;
55903194fc30SMatthew G. Knepley 
55913194fc30SMatthew G. Knepley           /* bottom */
55923194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
55939371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
55949371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
55953194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
55963194fc30SMatthew G. Knepley           /* middle */
55973194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
55983194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
55999371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
56009371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
56013194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
56023194fc30SMatthew G. Knepley           }
56033194fc30SMatthew G. Knepley           /* top */
56043194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
56059371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
56069371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
56073194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
56083194fc30SMatthew G. Knepley           foffset = offset;
56093194fc30SMatthew G. Knepley         }
561089eabcffSMatthew G. Knepley         break;
561189eabcffSMatthew G. Knepley       case 3:
561289eabcffSMatthew G. Knepley         /* The original hex closure is
561389eabcffSMatthew G. Knepley 
561489eabcffSMatthew G. Knepley          {c,
561589eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
561689eabcffSMatthew G. Knepley          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
561789eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
561889eabcffSMatthew G. Knepley          */
56199566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
562089eabcffSMatthew G. Knepley         /* The SEM order is
562189eabcffSMatthew G. Knepley          Bottom Slice
562289eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
562389eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
562489eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
562589eabcffSMatthew G. Knepley 
562689eabcffSMatthew G. Knepley          Middle Slice (j)
562789eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
562889eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
562989eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
563089eabcffSMatthew G. Knepley 
563189eabcffSMatthew G. Knepley          Top Slice
563289eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
563389eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
563489eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
563589eabcffSMatthew G. Knepley          */
563689eabcffSMatthew G. Knepley         {
563789eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
563889eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
563989eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
564089eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
564189eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
564289eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
564389eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
564489eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
564589eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
564689eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
564789eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
564889eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
564989eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
565089eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
565189eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
565289eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
565389eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
565489eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
565589eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
565689eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
565789eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
565889eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
565989eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
566089eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
566189eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
566289eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
566389eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
566489eabcffSMatthew G. Knepley           PetscInt       o, n;
566589eabcffSMatthew G. Knepley 
566689eabcffSMatthew G. Knepley           /* Bottom Slice */
566789eabcffSMatthew G. Knepley           /*   bottom */
566889eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
56699371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
56709371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
567189eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
567289eabcffSMatthew G. Knepley           /*   middle */
567389eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
567489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
56759371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
56769371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
56779371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
56789371c9d4SSatish Balay             }
567989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
56803194fc30SMatthew G. Knepley           }
568189eabcffSMatthew G. Knepley           /*   top */
568289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
56839371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
56849371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
568589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
568689eabcffSMatthew G. Knepley 
568789eabcffSMatthew G. Knepley           /* Middle Slice */
568889eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
568989eabcffSMatthew G. Knepley             /*   bottom */
569089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
56919371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
56929371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
569389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
569489eabcffSMatthew G. Knepley             /*   middle */
569589eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
569689eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
56979371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
56989371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
569989eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
570089eabcffSMatthew G. Knepley             }
570189eabcffSMatthew G. Knepley             /*   top */
570289eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
57039371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
57049371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
570589eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
570689eabcffSMatthew G. Knepley           }
570789eabcffSMatthew G. Knepley 
570889eabcffSMatthew G. Knepley           /* Top Slice */
570989eabcffSMatthew G. Knepley           /*   bottom */
571089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
57119371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
57129371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
571389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
571489eabcffSMatthew G. Knepley           /*   middle */
571589eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
571689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
57179371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
57189371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
571989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
572089eabcffSMatthew G. Knepley           }
572189eabcffSMatthew G. Knepley           /*   top */
572289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
57239371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
57249371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
572589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
572689eabcffSMatthew G. Knepley 
572789eabcffSMatthew G. Knepley           foffset = offset;
572889eabcffSMatthew G. Knepley         }
572989eabcffSMatthew G. Knepley         break;
5730d71ae5a4SJacob Faibussowitsch       default:
5731d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
573289eabcffSMatthew G. Knepley       }
573389eabcffSMatthew G. Knepley     }
573463a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
57353194fc30SMatthew G. Knepley     /* Check permutation */
57363194fc30SMatthew G. Knepley     {
57373194fc30SMatthew G. Knepley       PetscInt *check;
57383194fc30SMatthew G. Knepley 
57399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
57401dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
57411dca8a05SBarry Smith         check[i] = -1;
57421dca8a05SBarry Smith         PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);
57431dca8a05SBarry Smith       }
57443194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
57451dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
57469566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
57473194fc30SMatthew G. Knepley     }
57489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
5749a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5750a05c9aa3SJed Brown       PetscInt *loc_perm;
57519566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
5752a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
5753a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
5754a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
5755a05c9aa3SJed Brown       }
57569566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
5757a05c9aa3SJed Brown     }
5758bb197d40SJed Brown   }
57593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57603194fc30SMatthew G. Knepley }
57613194fc30SMatthew G. Knepley 
5762d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5763d71ae5a4SJacob Faibussowitsch {
5764e071409bSToby Isaac   PetscDS  prob;
5765e071409bSToby Isaac   PetscInt depth, Nf, h;
5766e071409bSToby Isaac   DMLabel  label;
5767e071409bSToby Isaac 
5768e071409bSToby Isaac   PetscFunctionBeginHot;
57699566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
5770e071409bSToby Isaac   Nf      = prob->Nf;
5771e071409bSToby Isaac   label   = dm->depthLabel;
5772e071409bSToby Isaac   *dspace = NULL;
5773e071409bSToby Isaac   if (field < Nf) {
5774e071409bSToby Isaac     PetscObject disc = prob->disc[field];
5775e071409bSToby Isaac 
5776e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
5777e071409bSToby Isaac       PetscDualSpace dsp;
5778e071409bSToby Isaac 
57799566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
57809566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
57819566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
5782e071409bSToby Isaac       h = depth - 1 - h;
5783e071409bSToby Isaac       if (h) {
57849566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
5785e071409bSToby Isaac       } else {
5786e071409bSToby Isaac         *dspace = dsp;
5787e071409bSToby Isaac       }
5788e071409bSToby Isaac     }
5789e071409bSToby Isaac   }
57903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5791e071409bSToby Isaac }
5792e071409bSToby Isaac 
5793d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5794d71ae5a4SJacob Faibussowitsch {
579528351e22SJed Brown   PetscScalar       *array;
579628351e22SJed Brown   const PetscScalar *vArray;
5797d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
57981a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
5799552f7358SJed Brown 
58001b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
58019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
58029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
58039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
58049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
58053f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
58069df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
58079df71ca4SMatthew G. Knepley       PetscInt dof;
5808d9917b9dSMatthew G. Knepley 
58099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
58109df71ca4SMatthew G. Knepley       size += dof;
58119df71ca4SMatthew G. Knepley     }
58129df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
58139df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
58142a3aaacfSMatthew G. Knepley       PetscInt       dof;
58155a1bb5cfSMatthew G. Knepley 
58165a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
58179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
58185a1bb5cfSMatthew G. Knepley       size += dof;
58195a1bb5cfSMatthew G. Knepley     }
58203f7cbbe7SMatthew G. Knepley     if (!values) {
58213f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
58223ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
58233f7cbbe7SMatthew G. Knepley     }
58249566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5825982e9ed1SMatthew G. Knepley   } else {
5826982e9ed1SMatthew G. Knepley     array = *values;
5827982e9ed1SMatthew G. Knepley   }
58289df71ca4SMatthew G. Knepley   size = 0;
582928351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
58309df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
58319df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
583228351e22SJed Brown     const PetscScalar *varr;
5833d9917b9dSMatthew G. Knepley 
58349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
58359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
58369df71ca4SMatthew G. Knepley     varr = &vArray[off];
5837ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
58389df71ca4SMatthew G. Knepley     size += dof;
58399df71ca4SMatthew G. Knepley   }
58409df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
58419df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
58429df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
58435a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
584428351e22SJed Brown     const PetscScalar *varr;
58455a1bb5cfSMatthew G. Knepley 
584652ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
58479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
58489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
58495a1bb5cfSMatthew G. Knepley     varr = &vArray[off];
58505a1bb5cfSMatthew G. Knepley     if (o >= 0) {
5851ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
58525a1bb5cfSMatthew G. Knepley     } else {
5853ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
58545a1bb5cfSMatthew G. Knepley     }
58559df71ca4SMatthew G. Knepley     size += dof;
58565a1bb5cfSMatthew G. Knepley   }
585728351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
58589df71ca4SMatthew G. Knepley   if (!*values) {
58595a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
58605a1bb5cfSMatthew G. Knepley     *values = array;
58619df71ca4SMatthew G. Knepley   } else {
586263a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
58638c312ff3SMatthew G. Knepley     *csize = size;
58649df71ca4SMatthew G. Knepley   }
58653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58665a1bb5cfSMatthew G. Knepley }
5867d9917b9dSMatthew G. Knepley 
586827f02ce8SMatthew G. Knepley /* Compress out points not in the section */
5869d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5870d71ae5a4SJacob Faibussowitsch {
587127f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
587227f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
587327f02ce8SMatthew G. Knepley 
58749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
587527f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
587627f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
587727f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
587827f02ce8SMatthew G. Knepley       points[q * 2]     = r;
587927f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
588027f02ce8SMatthew G. Knepley       ++q;
588127f02ce8SMatthew G. Knepley     }
588227f02ce8SMatthew G. Knepley   }
588327f02ce8SMatthew G. Knepley   *numPoints = q;
58843ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
588527f02ce8SMatthew G. Knepley }
588627f02ce8SMatthew G. Knepley 
588797529cf3SJed Brown /* Compressed closure does not apply closure permutation */
588807218a29SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5889d71ae5a4SJacob Faibussowitsch {
589027f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
5891923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
5892923c78e0SToby Isaac 
5893923c78e0SToby Isaac   PetscFunctionBeginHot;
58949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
589507218a29SMatthew G. Knepley   if (!ornt && *clPoints) {
5896923c78e0SToby Isaac     PetscInt dof, off;
5897923c78e0SToby Isaac 
58989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
58999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
59009566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
5901923c78e0SToby Isaac     np  = dof / 2;
5902923c78e0SToby Isaac     pts = (PetscInt *)&cla[off];
590327f02ce8SMatthew G. Knepley   } else {
590407218a29SMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
59059566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
5906923c78e0SToby Isaac   }
5907923c78e0SToby Isaac   *numPoints = np;
5908923c78e0SToby Isaac   *points    = pts;
5909923c78e0SToby Isaac   *clp       = cla;
59103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5911923c78e0SToby Isaac }
5912923c78e0SToby Isaac 
5913d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5914d71ae5a4SJacob Faibussowitsch {
5915923c78e0SToby Isaac   PetscFunctionBeginHot;
5916923c78e0SToby Isaac   if (!*clPoints) {
59179566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5918923c78e0SToby Isaac   } else {
59199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
5920923c78e0SToby Isaac   }
5921923c78e0SToby Isaac   *numPoints = 0;
5922923c78e0SToby Isaac   *points    = NULL;
5923923c78e0SToby Isaac   *clSec     = NULL;
5924923c78e0SToby Isaac   *clPoints  = NULL;
5925923c78e0SToby Isaac   *clp       = NULL;
59263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5927923c78e0SToby Isaac }
5928923c78e0SToby Isaac 
5929d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5930d71ae5a4SJacob Faibussowitsch {
59311a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
593297e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
593397e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
59341a271a75SMatthew G. Knepley 
59351a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5936fe02ba77SJed Brown   *size = 0;
59379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
593897e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
593997e99dd9SToby Isaac     const PetscInt     point = points[2 * p];
594097e99dd9SToby Isaac     const PetscInt    *perm  = perms ? perms[p] : NULL;
594197e99dd9SToby Isaac     const PetscScalar *flip  = flips ? flips[p] : NULL;
59421a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
59431a271a75SMatthew G. Knepley     const PetscScalar *varr;
59441a271a75SMatthew G. Knepley 
59459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
59469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
59471a271a75SMatthew G. Knepley     varr = &vArray[off];
594897e99dd9SToby Isaac     if (clperm) {
594997e99dd9SToby Isaac       if (perm) {
595097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
59511a271a75SMatthew G. Knepley       } else {
595297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
595397e99dd9SToby Isaac       }
595497e99dd9SToby Isaac       if (flip) {
595597e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
595697e99dd9SToby Isaac       }
595797e99dd9SToby Isaac     } else {
595897e99dd9SToby Isaac       if (perm) {
595997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
596097e99dd9SToby Isaac       } else {
596197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
596297e99dd9SToby Isaac       }
596397e99dd9SToby Isaac       if (flip) {
596497e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
59651a271a75SMatthew G. Knepley       }
59661a271a75SMatthew G. Knepley     }
596797e99dd9SToby Isaac     offset += dof;
596897e99dd9SToby Isaac   }
59699566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
59701a271a75SMatthew G. Knepley   *size = offset;
59713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59721a271a75SMatthew G. Knepley }
59731a271a75SMatthew G. Knepley 
5974d71ae5a4SJacob Faibussowitsch 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[])
5975d71ae5a4SJacob Faibussowitsch {
59761a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
59771a271a75SMatthew G. Knepley 
59781a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5979fe02ba77SJed Brown   *size = 0;
59801a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
598197e99dd9SToby Isaac     PetscInt            p;
598297e99dd9SToby Isaac     const PetscInt    **perms = NULL;
598397e99dd9SToby Isaac     const PetscScalar **flips = NULL;
59841a271a75SMatthew G. Knepley 
59859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
598697e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
598797e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
598897e99dd9SToby Isaac       PetscInt           fdof, foff, b;
59891a271a75SMatthew G. Knepley       const PetscScalar *varr;
599097e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
599197e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
59921a271a75SMatthew G. Knepley 
59939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
59949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
59951a271a75SMatthew G. Knepley       varr = &vArray[foff];
599697e99dd9SToby Isaac       if (clperm) {
59979371c9d4SSatish Balay         if (perm) {
5998ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
59991a271a75SMatthew G. Knepley         } else {
6000ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
60019371c9d4SSatish Balay         }
60029371c9d4SSatish Balay         if (flip) {
6003ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
60049371c9d4SSatish Balay         }
60059371c9d4SSatish Balay       } else {
60069371c9d4SSatish Balay         if (perm) {
6007ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
60089371c9d4SSatish Balay         } else {
6009ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
60109371c9d4SSatish Balay         }
60119371c9d4SSatish Balay         if (flip) {
6012ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
60139371c9d4SSatish Balay         }
60141a271a75SMatthew G. Knepley       }
601597e99dd9SToby Isaac       offset += fdof;
60161a271a75SMatthew G. Knepley     }
60179566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
60181a271a75SMatthew G. Knepley   }
60191a271a75SMatthew G. Knepley   *size = offset;
60203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60211a271a75SMatthew G. Knepley }
60221a271a75SMatthew G. Knepley 
602307218a29SMatthew G. Knepley PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
602407218a29SMatthew G. Knepley {
602507218a29SMatthew G. Knepley   PetscSection    clSection;
602607218a29SMatthew G. Knepley   IS              clPoints;
602707218a29SMatthew G. Knepley   PetscInt       *points = NULL;
602807218a29SMatthew G. Knepley   const PetscInt *clp, *perm;
602907218a29SMatthew G. Knepley   PetscInt        depth, numFields, numPoints, asize;
603007218a29SMatthew G. Knepley 
603107218a29SMatthew G. Knepley   PetscFunctionBeginHot;
603207218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
603307218a29SMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
603407218a29SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
603507218a29SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
603607218a29SMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
603707218a29SMatthew G. Knepley   PetscCall(PetscSectionGetNumFields(section, &numFields));
603807218a29SMatthew G. Knepley   if (depth == 1 && numFields < 2) {
603907218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
604007218a29SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
604107218a29SMatthew G. Knepley   }
604207218a29SMatthew G. Knepley   /* Get points */
604307218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
604407218a29SMatthew G. Knepley   /* Get sizes */
604507218a29SMatthew G. Knepley   asize = 0;
604607218a29SMatthew G. Knepley   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
604707218a29SMatthew G. Knepley     PetscInt dof;
604807218a29SMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, points[p], &dof));
604907218a29SMatthew G. Knepley     asize += dof;
605007218a29SMatthew G. Knepley   }
605107218a29SMatthew G. Knepley   if (values) {
605207218a29SMatthew G. Knepley     const PetscScalar *vArray;
605307218a29SMatthew G. Knepley     PetscInt           size;
605407218a29SMatthew G. Knepley 
605507218a29SMatthew G. Knepley     if (*values) {
605607218a29SMatthew G. Knepley       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);
605707218a29SMatthew G. Knepley     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
605807218a29SMatthew G. Knepley     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
605907218a29SMatthew G. Knepley     PetscCall(VecGetArrayRead(v, &vArray));
606007218a29SMatthew G. Knepley     /* Get values */
606107218a29SMatthew G. Knepley     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
606207218a29SMatthew G. Knepley     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
606307218a29SMatthew G. Knepley     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
606407218a29SMatthew G. Knepley     /* Cleanup array */
606507218a29SMatthew G. Knepley     PetscCall(VecRestoreArrayRead(v, &vArray));
606607218a29SMatthew G. Knepley   }
606707218a29SMatthew G. Knepley   if (csize) *csize = asize;
606807218a29SMatthew G. Knepley   /* Cleanup points */
606907218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
607007218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
607107218a29SMatthew G. Knepley }
607207218a29SMatthew G. Knepley 
6073552f7358SJed Brown /*@C
6074552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6075552f7358SJed Brown 
6076552f7358SJed Brown   Not collective
6077552f7358SJed Brown 
6078552f7358SJed Brown   Input Parameters:
6079a1cb98faSBarry Smith + dm - The `DM`
608020f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6081552f7358SJed Brown . v - The local vector
6082a1cb98faSBarry Smith - point - The point in the `DM`
6083552f7358SJed Brown 
60846b867d5aSJose E. Roman   Input/Output Parameters:
608520f4b53cSBarry Smith + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
608620f4b53cSBarry Smith - values - An array to use for the values, or `NULL` to have it allocated automatically;
608720f4b53cSBarry Smith            if the user provided `NULL`, it is a borrowed array and should not be freed
608822c1ee49SMatthew G. Knepley 
6089552f7358SJed Brown   Level: intermediate
6090552f7358SJed Brown 
6091a1cb98faSBarry Smith   Notes:
609220f4b53cSBarry Smith   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6093a1cb98faSBarry Smith   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6094a1cb98faSBarry Smith   assembly function, and a user may already have allocated storage for this operation.
6095a1cb98faSBarry Smith 
6096a1cb98faSBarry Smith   A typical use could be
6097a1cb98faSBarry Smith .vb
6098a1cb98faSBarry Smith    values = NULL;
6099a1cb98faSBarry Smith    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6100a1cb98faSBarry Smith    for (cl = 0; cl < clSize; ++cl) {
6101a1cb98faSBarry Smith      <Compute on closure>
6102a1cb98faSBarry Smith    }
6103a1cb98faSBarry Smith    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6104a1cb98faSBarry Smith .ve
6105a1cb98faSBarry Smith   or
6106a1cb98faSBarry Smith .vb
6107a1cb98faSBarry Smith    PetscMalloc1(clMaxSize, &values);
6108a1cb98faSBarry Smith    for (p = pStart; p < pEnd; ++p) {
6109a1cb98faSBarry Smith      clSize = clMaxSize;
6110a1cb98faSBarry Smith      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6111a1cb98faSBarry Smith      for (cl = 0; cl < clSize; ++cl) {
6112a1cb98faSBarry Smith        <Compute on closure>
6113a1cb98faSBarry Smith      }
6114a1cb98faSBarry Smith    }
6115a1cb98faSBarry Smith    PetscFree(values);
6116a1cb98faSBarry Smith .ve
6117a1cb98faSBarry Smith 
6118a1cb98faSBarry Smith   Fortran Note:
611920f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6120a1cb98faSBarry Smith 
61211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6122552f7358SJed Brown @*/
6123d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6124d71ae5a4SJacob Faibussowitsch {
6125d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
612607218a29SMatthew G. Knepley   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, v, point, 0, csize, values));
61273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6128552f7358SJed Brown }
6129552f7358SJed Brown 
6130d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6131d71ae5a4SJacob Faibussowitsch {
6132e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6133e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6134e5c487bfSMatthew G. Knepley   IS                 clPoints;
6135e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6136e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6137e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6138c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6139c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6140e5c487bfSMatthew G. Knepley 
6141e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6142e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
61439566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6144e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6145e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
61469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
61479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
61489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6149e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
61509566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
61513ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6152e5c487bfSMatthew G. Knepley   }
6153e5c487bfSMatthew G. Knepley   /* Get points */
615407218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6155c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6156c459fbc1SJed Brown     PetscInt dof;
61579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6158c459fbc1SJed Brown     clsize += dof;
6159c459fbc1SJed Brown   }
61609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6161e5c487bfSMatthew G. Knepley   /* Filter points */
6162e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6163e5c487bfSMatthew G. Knepley     PetscInt dep;
6164e5c487bfSMatthew G. Knepley 
61659566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6166e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6167e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6168e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6169e5c487bfSMatthew G. Knepley     ++Np;
6170e5c487bfSMatthew G. Knepley   }
6171e5c487bfSMatthew G. Knepley   /* Get array */
6172e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6173e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6174e5c487bfSMatthew G. Knepley 
6175e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
61769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6177e5c487bfSMatthew G. Knepley       asize += dof;
6178e5c487bfSMatthew G. Knepley     }
6179e5c487bfSMatthew G. Knepley     if (!values) {
61809566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6181e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
61823ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
6183e5c487bfSMatthew G. Knepley     }
61849566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6185e5c487bfSMatthew G. Knepley   } else {
6186e5c487bfSMatthew G. Knepley     array = *values;
6187e5c487bfSMatthew G. Knepley   }
61889566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6189e5c487bfSMatthew G. Knepley   /* Get values */
61909566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
61919566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6192e5c487bfSMatthew G. Knepley   /* Cleanup points */
61939566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6194e5c487bfSMatthew G. Knepley   /* Cleanup array */
61959566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6196e5c487bfSMatthew G. Knepley   if (!*values) {
6197e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6198e5c487bfSMatthew G. Knepley     *values = array;
6199e5c487bfSMatthew G. Knepley   } else {
620063a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6201e5c487bfSMatthew G. Knepley     *csize = size;
6202e5c487bfSMatthew G. Knepley   }
62033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6204e5c487bfSMatthew G. Knepley }
6205e5c487bfSMatthew G. Knepley 
6206552f7358SJed Brown /*@C
6207552f7358SJed Brown   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6208552f7358SJed Brown 
6209552f7358SJed Brown   Not collective
6210552f7358SJed Brown 
6211552f7358SJed Brown   Input Parameters:
6212a1cb98faSBarry Smith + dm - The `DM`
621320f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6214552f7358SJed Brown . v - The local vector
6215a1cb98faSBarry Smith . point - The point in the `DM`
621620f4b53cSBarry Smith . csize - The number of values in the closure, or `NULL`
6217552f7358SJed Brown - values - The array of values, which is a borrowed array and should not be freed
6218552f7358SJed Brown 
6219552f7358SJed Brown   Level: intermediate
6220552f7358SJed Brown 
6221a1cb98faSBarry Smith   Note:
622220f4b53cSBarry Smith   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6223a1cb98faSBarry Smith 
6224a1cb98faSBarry Smith   Fortran Note:
622520f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6226a1cb98faSBarry Smith 
62271cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6228552f7358SJed Brown @*/
6229d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6230d71ae5a4SJacob Faibussowitsch {
6231552f7358SJed Brown   PetscInt size = 0;
6232552f7358SJed Brown 
6233552f7358SJed Brown   PetscFunctionBegin;
6234552f7358SJed Brown   /* Should work without recalculating size */
62359566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6236c9fdaa05SMatthew G. Knepley   *values = NULL;
62373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6238552f7358SJed Brown }
6239552f7358SJed Brown 
6240d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6241d71ae5a4SJacob Faibussowitsch {
62429371c9d4SSatish Balay   *x += y;
62439371c9d4SSatish Balay }
6244d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6245d71ae5a4SJacob Faibussowitsch {
62469371c9d4SSatish Balay   *x = y;
62479371c9d4SSatish Balay }
6248552f7358SJed Brown 
6249d71ae5a4SJacob Faibussowitsch 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[])
6250d71ae5a4SJacob Faibussowitsch {
6251552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6252552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6253552f7358SJed Brown   PetscScalar    *a;
6254552f7358SJed Brown   PetscInt        off, cind = 0, k;
6255552f7358SJed Brown 
6256552f7358SJed Brown   PetscFunctionBegin;
62579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
62589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6259552f7358SJed Brown   a = &array[off];
6260552f7358SJed Brown   if (!cdof || setBC) {
626197e99dd9SToby Isaac     if (clperm) {
62629371c9d4SSatish Balay       if (perm) {
6263ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6264552f7358SJed Brown       } else {
6265ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
62669371c9d4SSatish Balay       }
62679371c9d4SSatish Balay     } else {
62689371c9d4SSatish Balay       if (perm) {
6269ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
62709371c9d4SSatish Balay       } else {
6271ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
62729371c9d4SSatish Balay       }
6273552f7358SJed Brown     }
6274552f7358SJed Brown   } else {
62759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
627697e99dd9SToby Isaac     if (clperm) {
62779371c9d4SSatish Balay       if (perm) {
62789371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
62799371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
62809371c9d4SSatish Balay             ++cind;
62819371c9d4SSatish Balay             continue;
62829371c9d4SSatish Balay           }
628397e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6284552f7358SJed Brown         }
6285552f7358SJed Brown       } else {
6286552f7358SJed Brown         for (k = 0; k < dof; ++k) {
62879371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
62889371c9d4SSatish Balay             ++cind;
62899371c9d4SSatish Balay             continue;
62909371c9d4SSatish Balay           }
629197e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
629297e99dd9SToby Isaac         }
629397e99dd9SToby Isaac       }
629497e99dd9SToby Isaac     } else {
629597e99dd9SToby Isaac       if (perm) {
629697e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
62979371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
62989371c9d4SSatish Balay             ++cind;
62999371c9d4SSatish Balay             continue;
63009371c9d4SSatish Balay           }
630197e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
630297e99dd9SToby Isaac         }
630397e99dd9SToby Isaac       } else {
630497e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
63059371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
63069371c9d4SSatish Balay             ++cind;
63079371c9d4SSatish Balay             continue;
63089371c9d4SSatish Balay           }
630997e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
631097e99dd9SToby Isaac         }
6311552f7358SJed Brown       }
6312552f7358SJed Brown     }
6313552f7358SJed Brown   }
63143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6315552f7358SJed Brown }
6316552f7358SJed Brown 
6317d71ae5a4SJacob Faibussowitsch 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[])
6318d71ae5a4SJacob Faibussowitsch {
6319a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6320a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6321a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6322a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6323a5e93ea8SMatthew G. Knepley 
6324a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
63259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
63269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6327a5e93ea8SMatthew G. Knepley   a = &array[off];
6328a5e93ea8SMatthew G. Knepley   if (cdof) {
63299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
633097e99dd9SToby Isaac     if (clperm) {
633197e99dd9SToby Isaac       if (perm) {
6332a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6333a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
633497e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
633597e99dd9SToby Isaac             cind++;
6336a5e93ea8SMatthew G. Knepley           }
6337a5e93ea8SMatthew G. Knepley         }
6338a5e93ea8SMatthew G. Knepley       } else {
6339a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6340a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
634197e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
634297e99dd9SToby Isaac             cind++;
634397e99dd9SToby Isaac           }
634497e99dd9SToby Isaac         }
634597e99dd9SToby Isaac       }
634697e99dd9SToby Isaac     } else {
634797e99dd9SToby Isaac       if (perm) {
634897e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
634997e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
635097e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
635197e99dd9SToby Isaac             cind++;
635297e99dd9SToby Isaac           }
635397e99dd9SToby Isaac         }
635497e99dd9SToby Isaac       } else {
635597e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
635697e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
635797e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
635897e99dd9SToby Isaac             cind++;
635997e99dd9SToby Isaac           }
6360a5e93ea8SMatthew G. Knepley         }
6361a5e93ea8SMatthew G. Knepley       }
6362a5e93ea8SMatthew G. Knepley     }
6363a5e93ea8SMatthew G. Knepley   }
63643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6365a5e93ea8SMatthew G. Knepley }
6366a5e93ea8SMatthew G. Knepley 
6367d71ae5a4SJacob Faibussowitsch 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[])
6368d71ae5a4SJacob Faibussowitsch {
6369552f7358SJed Brown   PetscScalar    *a;
63701a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
63711a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
637297e99dd9SToby Isaac   PetscInt        cind = 0, b;
6373552f7358SJed Brown 
6374552f7358SJed Brown   PetscFunctionBegin;
63759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
63769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
63779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
63781a271a75SMatthew G. Knepley   a = &array[foff];
6379552f7358SJed Brown   if (!fcdof || setBC) {
638097e99dd9SToby Isaac     if (clperm) {
63819371c9d4SSatish Balay       if (perm) {
6382ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6383552f7358SJed Brown       } else {
6384ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
63859371c9d4SSatish Balay       }
63869371c9d4SSatish Balay     } else {
63879371c9d4SSatish Balay       if (perm) {
6388ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
63899371c9d4SSatish Balay       } else {
6390ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
63919371c9d4SSatish Balay       }
6392552f7358SJed Brown     }
6393552f7358SJed Brown   } else {
63949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
639597e99dd9SToby Isaac     if (clperm) {
639697e99dd9SToby Isaac       if (perm) {
639797e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
63989371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
63999371c9d4SSatish Balay             ++cind;
64009371c9d4SSatish Balay             continue;
64019371c9d4SSatish Balay           }
640297e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6403552f7358SJed Brown         }
6404552f7358SJed Brown       } else {
640597e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
64069371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
64079371c9d4SSatish Balay             ++cind;
64089371c9d4SSatish Balay             continue;
64099371c9d4SSatish Balay           }
641097e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
641197e99dd9SToby Isaac         }
641297e99dd9SToby Isaac       }
641397e99dd9SToby Isaac     } else {
641497e99dd9SToby Isaac       if (perm) {
641597e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
64169371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
64179371c9d4SSatish Balay             ++cind;
64189371c9d4SSatish Balay             continue;
64199371c9d4SSatish Balay           }
642097e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
642197e99dd9SToby Isaac         }
642297e99dd9SToby Isaac       } else {
642397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
64249371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
64259371c9d4SSatish Balay             ++cind;
64269371c9d4SSatish Balay             continue;
64279371c9d4SSatish Balay           }
642897e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6429552f7358SJed Brown         }
6430552f7358SJed Brown       }
6431552f7358SJed Brown     }
6432552f7358SJed Brown   }
64331a271a75SMatthew G. Knepley   *offset += fdof;
64343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6435552f7358SJed Brown }
6436552f7358SJed Brown 
6437d71ae5a4SJacob Faibussowitsch 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[])
6438d71ae5a4SJacob Faibussowitsch {
6439a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
64401a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
64411a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
64425da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6443ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6444a5e93ea8SMatthew G. Knepley 
6445a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
64469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
64479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
64489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
64499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
64501a271a75SMatthew G. Knepley   a = &array[foff];
6451a5e93ea8SMatthew G. Knepley   if (fcdof) {
6452ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
64539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
645497e99dd9SToby Isaac     if (clperm) {
645597e99dd9SToby Isaac       if (perm) {
6456ba322698SMatthew G. Knepley         if (comps) {
6457ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6458ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
64599371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
64609371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
64619371c9d4SSatish Balay               ncSet = PETSC_TRUE;
64629371c9d4SSatish Balay             }
64639371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
64649371c9d4SSatish Balay               ++cind;
64659371c9d4SSatish Balay               fcSet = PETSC_TRUE;
64669371c9d4SSatish Balay             }
6467ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6468ba322698SMatthew G. Knepley           }
6469ba322698SMatthew G. Knepley         } else {
647097e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
647197e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
647297e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6473a5e93ea8SMatthew G. Knepley               ++cind;
6474a5e93ea8SMatthew G. Knepley             }
6475a5e93ea8SMatthew G. Knepley           }
6476ba322698SMatthew G. Knepley         }
6477ba322698SMatthew G. Knepley       } else {
6478ba322698SMatthew G. Knepley         if (comps) {
6479ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6480ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
64819371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
64829371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
64839371c9d4SSatish Balay               ncSet = PETSC_TRUE;
64849371c9d4SSatish Balay             }
64859371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
64869371c9d4SSatish Balay               ++cind;
64879371c9d4SSatish Balay               fcSet = PETSC_TRUE;
64889371c9d4SSatish Balay             }
6489ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6490ba322698SMatthew G. Knepley           }
6491a5e93ea8SMatthew G. Knepley         } else {
649297e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
649397e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
649497e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
649597e99dd9SToby Isaac               ++cind;
649697e99dd9SToby Isaac             }
649797e99dd9SToby Isaac           }
649897e99dd9SToby Isaac         }
6499ba322698SMatthew G. Knepley       }
650097e99dd9SToby Isaac     } else {
650197e99dd9SToby Isaac       if (perm) {
6502ba322698SMatthew G. Knepley         if (comps) {
6503ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6504ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
65059371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
65069371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
65079371c9d4SSatish Balay               ncSet = PETSC_TRUE;
65089371c9d4SSatish Balay             }
65099371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
65109371c9d4SSatish Balay               ++cind;
65119371c9d4SSatish Balay               fcSet = PETSC_TRUE;
65129371c9d4SSatish Balay             }
6513ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6514ba322698SMatthew G. Knepley           }
6515ba322698SMatthew G. Knepley         } else {
651697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
651797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
651897e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
651997e99dd9SToby Isaac               ++cind;
652097e99dd9SToby Isaac             }
652197e99dd9SToby Isaac           }
6522ba322698SMatthew G. Knepley         }
6523ba322698SMatthew G. Knepley       } else {
6524ba322698SMatthew G. Knepley         if (comps) {
6525ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6526ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
65279371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
65289371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
65299371c9d4SSatish Balay               ncSet = PETSC_TRUE;
65309371c9d4SSatish Balay             }
65319371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
65329371c9d4SSatish Balay               ++cind;
65339371c9d4SSatish Balay               fcSet = PETSC_TRUE;
65349371c9d4SSatish Balay             }
6535ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6536ba322698SMatthew G. Knepley           }
653797e99dd9SToby Isaac         } else {
653897e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
653997e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
654097e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6541a5e93ea8SMatthew G. Knepley               ++cind;
6542a5e93ea8SMatthew G. Knepley             }
6543a5e93ea8SMatthew G. Knepley           }
6544a5e93ea8SMatthew G. Knepley         }
6545a5e93ea8SMatthew G. Knepley       }
6546a5e93ea8SMatthew G. Knepley     }
6547ba322698SMatthew G. Knepley   }
65481a271a75SMatthew G. Knepley   *offset += fdof;
65493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6550a5e93ea8SMatthew G. Knepley }
6551a5e93ea8SMatthew G. Knepley 
6552d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6553d71ae5a4SJacob Faibussowitsch {
6554552f7358SJed Brown   PetscScalar    *array;
65551b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
65561b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6557552f7358SJed Brown 
65581b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
65599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
65609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
65619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
65629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
65639566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6564b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6565b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
6566b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
6567b6ebb6e6SMatthew G. Knepley 
65689371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
65699371c9d4SSatish Balay       dof = 0;
65709371c9d4SSatish Balay       continue;
65719371c9d4SSatish Balay     }
65729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
6573b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
6574b6ebb6e6SMatthew G. Knepley     {
6575b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6576b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
6577b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
6578b6ebb6e6SMatthew G. Knepley 
65799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
65809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6581b6ebb6e6SMatthew G. Knepley       a = &array[coff];
6582b6ebb6e6SMatthew G. Knepley       if (!cdof) {
6583b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6584ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6585b6ebb6e6SMatthew G. Knepley         } else {
6586ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6587b6ebb6e6SMatthew G. Knepley         }
6588b6ebb6e6SMatthew G. Knepley       } else {
65899566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6590b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6591b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
65929371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
65939371c9d4SSatish Balay               ++cind;
65949371c9d4SSatish Balay               continue;
65959371c9d4SSatish Balay             }
6596b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
6597b6ebb6e6SMatthew G. Knepley           }
6598b6ebb6e6SMatthew G. Knepley         } else {
6599b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
66009371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
66019371c9d4SSatish Balay               ++cind;
66029371c9d4SSatish Balay               continue;
66039371c9d4SSatish Balay             }
6604b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
6605b6ebb6e6SMatthew G. Knepley           }
6606b6ebb6e6SMatthew G. Knepley         }
6607b6ebb6e6SMatthew G. Knepley       }
6608b6ebb6e6SMatthew G. Knepley     }
6609b6ebb6e6SMatthew G. Knepley   }
66109566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
66113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6612b6ebb6e6SMatthew G. Knepley }
66131b406b76SMatthew G. Knepley 
66141b406b76SMatthew G. Knepley /*@C
661520f4b53cSBarry Smith   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
66161b406b76SMatthew G. Knepley 
66171b406b76SMatthew G. Knepley   Not collective
66181b406b76SMatthew G. Knepley 
66191b406b76SMatthew G. Knepley   Input Parameters:
6620a1cb98faSBarry Smith + dm - The `DM`
662120f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
66221b406b76SMatthew G. Knepley . v - The local vector
662320f4b53cSBarry Smith . point - The point in the `DM`
66241b406b76SMatthew G. Knepley . values - The array of values
6625a1cb98faSBarry Smith - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6626a1cb98faSBarry Smith          where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
66271b406b76SMatthew G. Knepley 
66281b406b76SMatthew G. Knepley   Level: intermediate
66291b406b76SMatthew G. Knepley 
66301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
66311b406b76SMatthew G. Knepley @*/
6632d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6633d71ae5a4SJacob Faibussowitsch {
66341b406b76SMatthew G. Knepley   PetscSection    clSection;
66351b406b76SMatthew G. Knepley   IS              clPoints;
66361b406b76SMatthew G. Knepley   PetscScalar    *array;
66371b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
663827f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
6639c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
66401b406b76SMatthew G. Knepley 
66411a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
66421b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
66439566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
66441a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
66451a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
66469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
66479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
66481b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
66499566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
66503ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
66511b406b76SMatthew G. Knepley   }
66521a271a75SMatthew G. Knepley   /* Get points */
665307218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6654c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
6655c459fbc1SJed Brown     PetscInt dof;
66569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6657c459fbc1SJed Brown     clsize += dof;
6658c459fbc1SJed Brown   }
66599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
66601a271a75SMatthew G. Knepley   /* Get array */
66619566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
66621a271a75SMatthew G. Knepley   /* Get values */
6663ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
666497e99dd9SToby Isaac     PetscInt offset = 0, f;
6665552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
666697e99dd9SToby Isaac       const PetscInt    **perms = NULL;
666797e99dd9SToby Isaac       const PetscScalar **flips = NULL;
666897e99dd9SToby Isaac 
66699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6670552f7358SJed Brown       switch (mode) {
6671552f7358SJed Brown       case INSERT_VALUES:
667297e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
667397e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
667497e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
667597e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
66763ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
66779371c9d4SSatish Balay         }
66789371c9d4SSatish Balay         break;
6679552f7358SJed Brown       case INSERT_ALL_VALUES:
668097e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
668197e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
668297e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
668397e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
66843ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
66859371c9d4SSatish Balay         }
66869371c9d4SSatish Balay         break;
6687a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
668897e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
668997e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
669097e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
669197e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
66923ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
66939371c9d4SSatish Balay         }
66949371c9d4SSatish Balay         break;
6695552f7358SJed Brown       case ADD_VALUES:
669697e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
669797e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
669897e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
669997e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
67003ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
67019371c9d4SSatish Balay         }
67029371c9d4SSatish Balay         break;
6703552f7358SJed Brown       case ADD_ALL_VALUES:
670497e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
670597e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
670697e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
670797e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
67083ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
67099371c9d4SSatish Balay         }
67109371c9d4SSatish Balay         break;
6711304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
671297e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
671397e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
671497e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
671597e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
67163ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
67179371c9d4SSatish Balay         }
67189371c9d4SSatish Balay         break;
6719d71ae5a4SJacob Faibussowitsch       default:
6720d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6721552f7358SJed Brown       }
67229566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
67231a271a75SMatthew G. Knepley     }
6724552f7358SJed Brown   } else {
67251a271a75SMatthew G. Knepley     PetscInt            dof, off;
672697e99dd9SToby Isaac     const PetscInt    **perms = NULL;
672797e99dd9SToby Isaac     const PetscScalar **flips = NULL;
67281a271a75SMatthew G. Knepley 
67299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6730552f7358SJed Brown     switch (mode) {
6731552f7358SJed Brown     case INSERT_VALUES:
673297e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
673397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
673497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
673597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
67369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
67373ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
67389371c9d4SSatish Balay       }
67399371c9d4SSatish Balay       break;
6740552f7358SJed Brown     case INSERT_ALL_VALUES:
674197e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
674297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
674397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
674497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
67459566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
67463ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
67479371c9d4SSatish Balay       }
67489371c9d4SSatish Balay       break;
6749a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
675097e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
675197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
675297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
675397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
67549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
67553ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
67569371c9d4SSatish Balay       }
67579371c9d4SSatish Balay       break;
6758552f7358SJed Brown     case ADD_VALUES:
675997e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
676097e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
676197e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
676297e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
67639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
67643ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
67659371c9d4SSatish Balay       }
67669371c9d4SSatish Balay       break;
6767552f7358SJed Brown     case ADD_ALL_VALUES:
676897e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
676997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
677097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
677197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
67729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
67733ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
67749371c9d4SSatish Balay       }
67759371c9d4SSatish Balay       break;
6776304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
677797e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
677897e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
677997e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
678097e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
67819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
67823ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
67839371c9d4SSatish Balay       }
67849371c9d4SSatish Balay       break;
6785d71ae5a4SJacob Faibussowitsch     default:
6786d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6787552f7358SJed Brown     }
67889566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6789552f7358SJed Brown   }
67901a271a75SMatthew G. Knepley   /* Cleanup points */
67919566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
67921a271a75SMatthew G. Knepley   /* Cleanup array */
67939566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
67943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6795552f7358SJed Brown }
6796552f7358SJed Brown 
6797cfb853baSMatthew G. Knepley PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6798cfb853baSMatthew G. Knepley {
6799cfb853baSMatthew G. Knepley   const PetscInt *supp, *cone;
6800cfb853baSMatthew G. Knepley   PetscScalar    *a;
6801cfb853baSMatthew G. Knepley   PetscInt        dim, Ns, dof, off, n = 0;
6802cfb853baSMatthew G. Knepley 
6803cfb853baSMatthew G. Knepley   PetscFunctionBegin;
6804cfb853baSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6805cfb853baSMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6806cfb853baSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6807cfb853baSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6808cfb853baSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) {
6809cfb853baSMatthew G. Knepley     PetscInt vStart, vEnd;
6810cfb853baSMatthew G. Knepley 
6811cfb853baSMatthew G. Knepley     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
6812cfb853baSMatthew G. Knepley     PetscCheck(point >= vStart && point < vEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " must be a vertex in [%" PetscInt_FMT ", %" PetscInt_FMT "]", point, vStart, vEnd);
6813cfb853baSMatthew G. Knepley   }
6814cfb853baSMatthew G. Knepley   PetscValidScalarPointer(values, 5);
6815cfb853baSMatthew G. Knepley 
6816cfb853baSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
6817cfb853baSMatthew G. Knepley   PetscCall(DMPlexGetSupportSize(dm, point, &Ns));
6818cfb853baSMatthew G. Knepley   PetscCall(DMPlexGetSupport(dm, point, &supp));
6819cfb853baSMatthew G. Knepley   PetscCheck(Ns == 2 * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has support size %" PetscInt_FMT " != %" PetscInt_FMT, point, Ns, 2 * dim);
6820cfb853baSMatthew G. Knepley   PetscCall(VecGetArray(v, &a));
6821cfb853baSMatthew G. Knepley   PetscCall(PetscSectionGetDof(section, point, &dof));
6822cfb853baSMatthew G. Knepley   PetscCall(PetscSectionGetOffset(section, point, &off));
6823cfb853baSMatthew G. Knepley   for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++];
6824cfb853baSMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
6825cfb853baSMatthew G. Knepley     // Left edge
6826cfb853baSMatthew G. Knepley     PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone));
6827cfb853baSMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, cone[0], &dof));
6828cfb853baSMatthew G. Knepley     PetscCall(PetscSectionGetOffset(section, cone[0], &off));
6829cfb853baSMatthew G. Knepley     for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++];
6830cfb853baSMatthew G. Knepley     // Right edge
6831cfb853baSMatthew G. Knepley     PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone));
6832cfb853baSMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, cone[1], &dof));
6833cfb853baSMatthew G. Knepley     PetscCall(PetscSectionGetOffset(section, cone[1], &off));
6834cfb853baSMatthew G. Knepley     for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++];
6835cfb853baSMatthew G. Knepley   }
6836cfb853baSMatthew G. Knepley   PetscCall(VecRestoreArray(v, &a));
68373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6838cfb853baSMatthew G. Knepley }
6839cfb853baSMatthew G. Knepley 
68405f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
6841d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
6842d71ae5a4SJacob Faibussowitsch {
68435f790a90SMatthew G. Knepley   PetscFunctionBegin;
684411cc89d2SBarry Smith   *contains = PETSC_TRUE;
68455f790a90SMatthew G. Knepley   if (label) {
6846d6177c40SToby Isaac     PetscInt fdof;
68475f790a90SMatthew G. Knepley 
684811cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
684911cc89d2SBarry Smith     if (!*contains) {
68509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
68515f790a90SMatthew G. Knepley       *offset += fdof;
68523ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
68535f790a90SMatthew G. Knepley     }
68545f790a90SMatthew G. Knepley   }
68553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
68565f790a90SMatthew G. Knepley }
68575f790a90SMatthew G. Knepley 
685897529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6859d71ae5a4SJacob Faibussowitsch 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)
6860d71ae5a4SJacob Faibussowitsch {
6861e07394fbSMatthew G. Knepley   PetscSection    clSection;
6862e07394fbSMatthew G. Knepley   IS              clPoints;
6863e07394fbSMatthew G. Knepley   PetscScalar    *array;
6864e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
686597529cf3SJed Brown   const PetscInt *clp;
6866e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
686797e99dd9SToby Isaac   PetscInt        offset = 0, f;
6868e07394fbSMatthew G. Knepley 
6869e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
6870e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
68719566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6872e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6873e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
68749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6875e07394fbSMatthew G. Knepley   /* Get points */
687607218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6877e07394fbSMatthew G. Knepley   /* Get array */
68789566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6879e07394fbSMatthew G. Knepley   /* Get values */
6880e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
688197e99dd9SToby Isaac     const PetscInt    **perms = NULL;
688297e99dd9SToby Isaac     const PetscScalar **flips = NULL;
688311cc89d2SBarry Smith     PetscBool           contains;
688497e99dd9SToby Isaac 
6885e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
6886e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
6887e07394fbSMatthew G. Knepley         PetscInt fdof;
68889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6889e07394fbSMatthew G. Knepley         offset += fdof;
6890e07394fbSMatthew G. Knepley       }
6891e07394fbSMatthew G. Knepley       continue;
6892e07394fbSMatthew G. Knepley     }
68939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6894e07394fbSMatthew G. Knepley     switch (mode) {
6895e07394fbSMatthew G. Knepley     case INSERT_VALUES:
689697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
689797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
689897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
689997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
690011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
690111cc89d2SBarry Smith         if (!contains) continue;
69029566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
69039371c9d4SSatish Balay       }
69049371c9d4SSatish Balay       break;
6905e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
690697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
690797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
690897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
690997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
691011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
691111cc89d2SBarry Smith         if (!contains) continue;
69129566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
69139371c9d4SSatish Balay       }
69149371c9d4SSatish Balay       break;
6915e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
691697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
691797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
691897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
691997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
692011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
692111cc89d2SBarry Smith         if (!contains) continue;
69229566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
69239371c9d4SSatish Balay       }
69249371c9d4SSatish Balay       break;
6925e07394fbSMatthew G. Knepley     case ADD_VALUES:
692697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
692797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
692897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
692997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
693011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
693111cc89d2SBarry Smith         if (!contains) continue;
69329566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
69339371c9d4SSatish Balay       }
69349371c9d4SSatish Balay       break;
6935e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
693697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
693797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
693897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
693997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
694011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
694111cc89d2SBarry Smith         if (!contains) continue;
69429566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
69439371c9d4SSatish Balay       }
69449371c9d4SSatish Balay       break;
6945d71ae5a4SJacob Faibussowitsch     default:
6946d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6947e07394fbSMatthew G. Knepley     }
69489566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6949e07394fbSMatthew G. Knepley   }
6950e07394fbSMatthew G. Knepley   /* Cleanup points */
69519566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6952e07394fbSMatthew G. Knepley   /* Cleanup array */
69539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
69543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6955e07394fbSMatthew G. Knepley }
6956e07394fbSMatthew G. Knepley 
6957d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6958d71ae5a4SJacob Faibussowitsch {
6959552f7358SJed Brown   PetscMPIInt rank;
6960552f7358SJed Brown   PetscInt    i, j;
6961552f7358SJed Brown 
6962552f7358SJed Brown   PetscFunctionBegin;
69639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
696463a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
696563a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
696663a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
6967b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
69683ba16761SJacob Faibussowitsch   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
6969b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
69709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6971b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
6972519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
69739566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
6974552f7358SJed Brown #else
69759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
6976552f7358SJed Brown #endif
6977552f7358SJed Brown     }
69789566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
6979552f7358SJed Brown   }
69803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6981552f7358SJed Brown }
6982552f7358SJed Brown 
698305586334SMatthew G. Knepley /*
698405586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
698505586334SMatthew G. Knepley 
698605586334SMatthew G. Knepley   Input Parameters:
698705586334SMatthew G. Knepley + section - The section for this data layout
698836fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
698905586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
699005586334SMatthew G. Knepley . off     - The global offset of this point
699105586334SMatthew G. Knepley . loff    - The local offset of each field
6992a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
699305586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
699405586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
699505586334SMatthew G. Knepley 
699605586334SMatthew G. Knepley   Output Parameter:
699705586334SMatthew G. Knepley . indices - Indices for dofs on this point
699805586334SMatthew G. Knepley 
699905586334SMatthew G. Knepley   Level: developer
700005586334SMatthew G. Knepley 
700105586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
700205586334SMatthew G. Knepley */
7003d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7004d71ae5a4SJacob Faibussowitsch {
7005e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
7006552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
7007552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7008552f7358SJed Brown   PetscInt        cind = 0, k;
7009552f7358SJed Brown 
7010552f7358SJed Brown   PetscFunctionBegin;
701108401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
70129566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
70139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7014552f7358SJed Brown   if (!cdof || setBC) {
701505586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
701605586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
701705586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
701805586334SMatthew G. Knepley 
701905586334SMatthew G. Knepley       indices[ind] = off + k;
7020552f7358SJed Brown     }
7021552f7358SJed Brown   } else {
70229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
70234acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
702405586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
702505586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
702605586334SMatthew G. Knepley 
70274acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
70284acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
702905586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
70304acb8e1eSToby Isaac         ++cind;
70314acb8e1eSToby Isaac       } else {
703236fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
7033552f7358SJed Brown       }
7034552f7358SJed Brown     }
7035552f7358SJed Brown   }
7036e6ccafaeSMatthew G Knepley   *loff += dof;
70373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7038552f7358SJed Brown }
7039552f7358SJed Brown 
70407e29afd2SMatthew G. Knepley /*
704136fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
70427e29afd2SMatthew G. Knepley 
704336fa2b79SJed Brown  Input Parameters:
704436fa2b79SJed Brown + section - a section (global or local)
704520f4b53cSBarry Smith - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
704636fa2b79SJed Brown . point - point within section
704736fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
704836fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
704936fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
705036fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
705136fa2b79SJed Brown . permsoff - offset
705236fa2b79SJed Brown - indperm - index permutation
705336fa2b79SJed Brown 
705436fa2b79SJed Brown  Output Parameter:
705536fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
705636fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
705736fa2b79SJed Brown 
705836fa2b79SJed Brown  Notes:
705936fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
706036fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
706136fa2b79SJed Brown  in the local vector.
706236fa2b79SJed Brown 
706336fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
706436fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
706536fa2b79SJed Brown 
706636fa2b79SJed Brown  Developer Note:
706736fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
706836fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
706936fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
707036fa2b79SJed Brown 
707136fa2b79SJed Brown  Example:
707236fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
707336fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
707436fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
707536fa2b79SJed Brown  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.
707636fa2b79SJed Brown 
707736fa2b79SJed Brown  Level: developer
70787e29afd2SMatthew G. Knepley */
7079d71ae5a4SJacob Faibussowitsch 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[])
7080d71ae5a4SJacob Faibussowitsch {
7081552f7358SJed Brown   PetscInt numFields, foff, f;
7082552f7358SJed Brown 
7083552f7358SJed Brown   PetscFunctionBegin;
708408401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
70859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7086552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
70874acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
7088552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
70894acb8e1eSToby Isaac     PetscInt        cind = 0, b;
70904acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7091552f7358SJed Brown 
70929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
70939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7094552f7358SJed Brown     if (!cfdof || setBC) {
709505586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
709605586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
709705586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
709805586334SMatthew G. Knepley 
709905586334SMatthew G. Knepley         indices[ind] = off + foff + b;
710005586334SMatthew G. Knepley       }
7101552f7358SJed Brown     } else {
71029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
710305586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
710405586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
710505586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
710605586334SMatthew G. Knepley 
71074acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
710805586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
7109552f7358SJed Brown           ++cind;
7110552f7358SJed Brown         } else {
711136fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7112552f7358SJed Brown         }
7113552f7358SJed Brown       }
7114552f7358SJed Brown     }
711536fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7116552f7358SJed Brown     foffs[f] += fdof;
7117552f7358SJed Brown   }
71183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7119552f7358SJed Brown }
7120552f7358SJed Brown 
71217e29afd2SMatthew G. Knepley /*
71227e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
71237e29afd2SMatthew G. Knepley 
71247e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7125645102dcSJed Brown 
7126645102dcSJed Brown  Notes:
7127645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7128645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
71297e29afd2SMatthew G. Knepley */
7130d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7131d71ae5a4SJacob Faibussowitsch {
71327e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
71337e29afd2SMatthew G. Knepley 
71347e29afd2SMatthew G. Knepley   PetscFunctionBegin;
71359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
71367e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
71377e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
71387e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
71397e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
71407e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
71417e29afd2SMatthew G. Knepley 
71429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
71439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
71449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7145645102dcSJed Brown     if (!cfdof) {
714605586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
714705586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
714805586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
714905586334SMatthew G. Knepley 
715005586334SMatthew G. Knepley         indices[ind] = foff + b;
715105586334SMatthew G. Knepley       }
71527e29afd2SMatthew G. Knepley     } else {
71539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
715405586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
715505586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
715605586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
715705586334SMatthew G. Knepley 
71587e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
715905586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
71607e29afd2SMatthew G. Knepley           ++cind;
71617e29afd2SMatthew G. Knepley         } else {
716205586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
71637e29afd2SMatthew G. Knepley         }
71647e29afd2SMatthew G. Knepley       }
71657e29afd2SMatthew G. Knepley     }
71667e29afd2SMatthew G. Knepley     foffs[f] += fdof;
71677e29afd2SMatthew G. Knepley   }
71683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
71697e29afd2SMatthew G. Knepley }
71707e29afd2SMatthew G. Knepley 
7171d71ae5a4SJacob Faibussowitsch 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)
7172d71ae5a4SJacob Faibussowitsch {
7173d3d1a6afSToby Isaac   Mat             cMat;
7174d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7175d3d1a6afSToby Isaac   IS              aIS;
7176d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7177d3d1a6afSToby Isaac   const PetscInt *anchors;
7178e17c06e0SMatthew G. Knepley   PetscInt        numFields, f, p, q, newP = 0;
7179d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7180d3d1a6afSToby Isaac   PetscInt       *newPoints, *indices, *newIndices;
7181d3d1a6afSToby Isaac   PetscInt        maxAnchor, maxDof;
7182d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7183d3d1a6afSToby Isaac   PetscInt       *pointMatOffsets[32];
7184d3d1a6afSToby Isaac   PetscInt       *newPointOffsets[32];
7185d3d1a6afSToby Isaac   PetscScalar    *pointMat[32];
71866ecaa68aSToby Isaac   PetscScalar    *newValues      = NULL, *tmpValues;
7187d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7188d3d1a6afSToby Isaac 
7189d3d1a6afSToby Isaac   PetscFunctionBegin;
7190d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7191d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
71929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7193d3d1a6afSToby Isaac 
71949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7195d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7196d3d1a6afSToby Isaac   if (aSec) {
71979566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
71989566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
71999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7200d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7201d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7202d3d1a6afSToby Isaac      * into the global matrix anyway) */
7203d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7204d3d1a6afSToby Isaac       PetscInt b    = points[p];
72054b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7206d3d1a6afSToby Isaac 
72079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7208ad540459SPierre Jolivet       if (!bSecDof) continue;
720948a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7210d3d1a6afSToby Isaac       if (bDof) {
7211d3d1a6afSToby Isaac         /* this point is constrained */
7212d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7213d3d1a6afSToby Isaac         PetscInt bOff, q;
7214d3d1a6afSToby Isaac 
7215d3d1a6afSToby Isaac         anyConstrained = PETSC_TRUE;
7216d3d1a6afSToby Isaac         newNumPoints += bDof;
72179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7218d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7219d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q];
7220d3d1a6afSToby Isaac           PetscInt aDof;
7221d3d1a6afSToby Isaac 
72229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7223d3d1a6afSToby Isaac           newNumIndices += aDof;
7224d3d1a6afSToby Isaac           for (f = 0; f < numFields; ++f) {
7225d3d1a6afSToby Isaac             PetscInt fDof;
7226d3d1a6afSToby Isaac 
72279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7228d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7229d3d1a6afSToby Isaac           }
7230d3d1a6afSToby Isaac         }
72319371c9d4SSatish Balay       } else {
7232d3d1a6afSToby Isaac         /* this point is not constrained */
7233d3d1a6afSToby Isaac         newNumPoints++;
72344b2f2278SToby Isaac         newNumIndices += bSecDof;
7235d3d1a6afSToby Isaac         for (f = 0; f < numFields; ++f) {
7236d3d1a6afSToby Isaac           PetscInt fDof;
7237d3d1a6afSToby Isaac 
72389566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7239d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7240d3d1a6afSToby Isaac         }
7241d3d1a6afSToby Isaac       }
7242d3d1a6afSToby Isaac     }
7243d3d1a6afSToby Isaac   }
7244d3d1a6afSToby Isaac   if (!anyConstrained) {
724572b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
724672b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
724772b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
724872b80496SMatthew G. Knepley     if (outValues) *outValues = NULL;
72499566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
72503ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7251d3d1a6afSToby Isaac   }
7252d3d1a6afSToby Isaac 
72536ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
72546ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
72556ecaa68aSToby Isaac 
7256f13f9184SToby Isaac   for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7257d3d1a6afSToby Isaac 
72586ecaa68aSToby Isaac   if (!outPoints && !outValues) {
72596ecaa68aSToby Isaac     if (offsets) {
7260ad540459SPierre Jolivet       for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
72616ecaa68aSToby Isaac     }
72629566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
72633ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
72646ecaa68aSToby Isaac   }
72656ecaa68aSToby Isaac 
72661dca8a05SBarry Smith   PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices);
7267d3d1a6afSToby Isaac 
72689566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7269d3d1a6afSToby Isaac 
7270d3d1a6afSToby Isaac   /* workspaces */
7271d3d1a6afSToby Isaac   if (numFields) {
7272d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
72739566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
72749566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7275d3d1a6afSToby Isaac     }
72769371c9d4SSatish Balay   } else {
72779566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
72789566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0]));
7279d3d1a6afSToby Isaac   }
7280d3d1a6afSToby Isaac 
7281d3d1a6afSToby Isaac   /* get workspaces for the point-to-point matrices */
7282d3d1a6afSToby Isaac   if (numFields) {
72834b2f2278SToby Isaac     PetscInt totalOffset, totalMatOffset;
72844b2f2278SToby Isaac 
7285d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7286d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
72874b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7288d3d1a6afSToby Isaac 
72899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
72904b2f2278SToby Isaac       if (!bSecDof) {
72914b2f2278SToby Isaac         for (f = 0; f < numFields; f++) {
72924b2f2278SToby Isaac           newPointOffsets[f][p + 1] = 0;
72934b2f2278SToby Isaac           pointMatOffsets[f][p + 1] = 0;
72944b2f2278SToby Isaac         }
72954b2f2278SToby Isaac         continue;
72964b2f2278SToby Isaac       }
729748a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7298d3d1a6afSToby Isaac       if (bDof) {
7299d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7300d3d1a6afSToby Isaac           PetscInt fDof, q, bOff, allFDof = 0;
7301d3d1a6afSToby Isaac 
73029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
73039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7304d3d1a6afSToby Isaac           for (q = 0; q < bDof; q++) {
7305d3d1a6afSToby Isaac             PetscInt a = anchors[bOff + q];
7306d3d1a6afSToby Isaac             PetscInt aFDof;
7307d3d1a6afSToby Isaac 
73089566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
7309d3d1a6afSToby Isaac             allFDof += aFDof;
7310d3d1a6afSToby Isaac           }
7311d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = allFDof;
7312d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = fDof * allFDof;
7313d3d1a6afSToby Isaac         }
73149371c9d4SSatish Balay       } else {
7315d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7316d3d1a6afSToby Isaac           PetscInt fDof;
7317d3d1a6afSToby Isaac 
73189566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7319d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = fDof;
7320d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = 0;
7321d3d1a6afSToby Isaac         }
7322d3d1a6afSToby Isaac       }
7323d3d1a6afSToby Isaac     }
73244b2f2278SToby Isaac     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
73254b2f2278SToby Isaac       newPointOffsets[f][0] = totalOffset;
73264b2f2278SToby Isaac       pointMatOffsets[f][0] = totalMatOffset;
7327d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7328d3d1a6afSToby Isaac         newPointOffsets[f][p + 1] += newPointOffsets[f][p];
7329d3d1a6afSToby Isaac         pointMatOffsets[f][p + 1] += pointMatOffsets[f][p];
7330d3d1a6afSToby Isaac       }
733119f70fd5SToby Isaac       totalOffset    = newPointOffsets[f][numPoints];
733219f70fd5SToby Isaac       totalMatOffset = pointMatOffsets[f][numPoints];
73339566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7334d3d1a6afSToby Isaac     }
73359371c9d4SSatish Balay   } else {
7336d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7337d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
73384b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7339d3d1a6afSToby Isaac 
73409566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
73414b2f2278SToby Isaac       if (!bSecDof) {
73424b2f2278SToby Isaac         newPointOffsets[0][p + 1] = 0;
73434b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = 0;
73444b2f2278SToby Isaac         continue;
73454b2f2278SToby Isaac       }
734648a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7347d3d1a6afSToby Isaac       if (bDof) {
73484b2f2278SToby Isaac         PetscInt bOff, q, allDof = 0;
7349d3d1a6afSToby Isaac 
73509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7351d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7352d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aDof;
7353d3d1a6afSToby Isaac 
73549566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7355d3d1a6afSToby Isaac           allDof += aDof;
7356d3d1a6afSToby Isaac         }
7357d3d1a6afSToby Isaac         newPointOffsets[0][p + 1] = allDof;
73584b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = bSecDof * allDof;
73599371c9d4SSatish Balay       } else {
73604b2f2278SToby Isaac         newPointOffsets[0][p + 1] = bSecDof;
7361d3d1a6afSToby Isaac         pointMatOffsets[0][p + 1] = 0;
7362d3d1a6afSToby Isaac       }
7363d3d1a6afSToby Isaac     }
7364d3d1a6afSToby Isaac     newPointOffsets[0][0] = 0;
7365d3d1a6afSToby Isaac     pointMatOffsets[0][0] = 0;
7366d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7367d3d1a6afSToby Isaac       newPointOffsets[0][p + 1] += newPointOffsets[0][p];
7368d3d1a6afSToby Isaac       pointMatOffsets[0][p + 1] += pointMatOffsets[0][p];
7369d3d1a6afSToby Isaac     }
73709566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7371d3d1a6afSToby Isaac   }
7372d3d1a6afSToby Isaac 
73736ecaa68aSToby Isaac   /* output arrays */
73749566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
73756ecaa68aSToby Isaac 
7376d3d1a6afSToby Isaac   /* get the point-to-point matrices; construct newPoints */
73779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
73789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
73799566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices));
73809566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7381d3d1a6afSToby Isaac   if (numFields) {
7382d3d1a6afSToby Isaac     for (p = 0, newP = 0; p < numPoints; p++) {
7383d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7384d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
73854b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7386d3d1a6afSToby Isaac 
73879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7388ad540459SPierre Jolivet       if (!bSecDof) continue;
738948a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7390d3d1a6afSToby Isaac       if (bDof) {
7391d3d1a6afSToby Isaac         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
7392d3d1a6afSToby Isaac 
7393d3d1a6afSToby Isaac         fStart[0] = 0;
7394d3d1a6afSToby Isaac         fEnd[0]   = 0;
7395d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7396d3d1a6afSToby Isaac           PetscInt fDof;
7397d3d1a6afSToby Isaac 
73989566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7399d3d1a6afSToby Isaac           fStart[f + 1] = fStart[f] + fDof;
7400d3d1a6afSToby Isaac           fEnd[f + 1]   = fStart[f + 1];
7401d3d1a6afSToby Isaac         }
74029566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
74039566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
7404d3d1a6afSToby Isaac 
7405d3d1a6afSToby Isaac         fAnchorStart[0] = 0;
7406d3d1a6afSToby Isaac         fAnchorEnd[0]   = 0;
7407d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7408d3d1a6afSToby Isaac           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7409d3d1a6afSToby Isaac 
7410d3d1a6afSToby Isaac           fAnchorStart[f + 1] = fAnchorStart[f] + fDof;
7411d3d1a6afSToby Isaac           fAnchorEnd[f + 1]   = fAnchorStart[f + 1];
7412d3d1a6afSToby Isaac         }
74139566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7414d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7415d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7416d3d1a6afSToby Isaac 
7417d3d1a6afSToby Isaac           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7418d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7419d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
74209566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
74219566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7422d3d1a6afSToby Isaac         }
7423d3d1a6afSToby Isaac         newP += bDof;
7424d3d1a6afSToby Isaac 
74256ecaa68aSToby Isaac         if (outValues) {
7426d3d1a6afSToby Isaac           /* get the point-to-point submatrix */
742748a46eb9SPierre Jolivet           for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p]));
7428d3d1a6afSToby Isaac         }
74299371c9d4SSatish Balay       } else {
7430d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7431d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7432d3d1a6afSToby Isaac         newP++;
7433d3d1a6afSToby Isaac       }
7434d3d1a6afSToby Isaac     }
7435d3d1a6afSToby Isaac   } else {
7436d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7437d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7438d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
74394b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7440d3d1a6afSToby Isaac 
74419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7442ad540459SPierre Jolivet       if (!bSecDof) continue;
744348a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7444d3d1a6afSToby Isaac       if (bDof) {
7445d3d1a6afSToby Isaac         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7446d3d1a6afSToby Isaac 
74479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
74489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7449d3d1a6afSToby Isaac 
74509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7451d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7452d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7453d3d1a6afSToby Isaac 
7454d3d1a6afSToby Isaac           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7455d3d1a6afSToby Isaac 
7456d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7457d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
74589566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
74599566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7460d3d1a6afSToby Isaac         }
7461d3d1a6afSToby Isaac         newP += bDof;
7462d3d1a6afSToby Isaac 
7463d3d1a6afSToby Isaac         /* get the point-to-point submatrix */
746448a46eb9SPierre Jolivet         if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p]));
74659371c9d4SSatish Balay       } else {
7466d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7467d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7468d3d1a6afSToby Isaac         newP++;
7469d3d1a6afSToby Isaac       }
7470d3d1a6afSToby Isaac     }
7471d3d1a6afSToby Isaac   }
7472d3d1a6afSToby Isaac 
74736ecaa68aSToby Isaac   if (outValues) {
74749566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
74759566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices));
7476d3d1a6afSToby Isaac     /* multiply constraints on the right */
7477d3d1a6afSToby Isaac     if (numFields) {
7478d3d1a6afSToby Isaac       for (f = 0; f < numFields; f++) {
7479d3d1a6afSToby Isaac         PetscInt oldOff = offsets[f];
7480d3d1a6afSToby Isaac 
7481d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7482d3d1a6afSToby Isaac           PetscInt cStart = newPointOffsets[f][p];
7483d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7484d3d1a6afSToby Isaac           PetscInt c, r, k;
7485d3d1a6afSToby Isaac           PetscInt dof;
7486d3d1a6afSToby Isaac 
74879566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7488ad540459SPierre Jolivet           if (!dof) continue;
7489d3d1a6afSToby Isaac           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7490d3d1a6afSToby Isaac             PetscInt           nCols = newPointOffsets[f][p + 1] - cStart;
7491d3d1a6afSToby Isaac             const PetscScalar *mat   = pointMat[f] + pointMatOffsets[f][p];
7492d3d1a6afSToby Isaac 
7493d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7494d3d1a6afSToby Isaac               for (c = 0; c < nCols; c++) {
7495ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7496d3d1a6afSToby Isaac               }
7497d3d1a6afSToby Isaac             }
74989371c9d4SSatish Balay           } else {
7499d3d1a6afSToby Isaac             /* copy this column as is */
7500d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7501ad540459SPierre Jolivet               for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7502d3d1a6afSToby Isaac             }
7503d3d1a6afSToby Isaac           }
7504d3d1a6afSToby Isaac           oldOff += dof;
7505d3d1a6afSToby Isaac         }
7506d3d1a6afSToby Isaac       }
75079371c9d4SSatish Balay     } else {
7508d3d1a6afSToby Isaac       PetscInt oldOff = 0;
7509d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7510d3d1a6afSToby Isaac         PetscInt cStart = newPointOffsets[0][p];
7511d3d1a6afSToby Isaac         PetscInt b      = points[2 * p];
7512d3d1a6afSToby Isaac         PetscInt c, r, k;
7513d3d1a6afSToby Isaac         PetscInt dof;
7514d3d1a6afSToby Isaac 
75159566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, b, &dof));
7516ad540459SPierre Jolivet         if (!dof) continue;
7517d3d1a6afSToby Isaac         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7518d3d1a6afSToby Isaac           PetscInt           nCols = newPointOffsets[0][p + 1] - cStart;
7519d3d1a6afSToby Isaac           const PetscScalar *mat   = pointMat[0] + pointMatOffsets[0][p];
7520d3d1a6afSToby Isaac 
7521d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7522d3d1a6afSToby Isaac             for (c = 0; c < nCols; c++) {
7523ad540459SPierre Jolivet               for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7524d3d1a6afSToby Isaac             }
7525d3d1a6afSToby Isaac           }
75269371c9d4SSatish Balay         } else {
7527d3d1a6afSToby Isaac           /* copy this column as is */
7528d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7529ad540459SPierre Jolivet             for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7530d3d1a6afSToby Isaac           }
7531d3d1a6afSToby Isaac         }
7532d3d1a6afSToby Isaac         oldOff += dof;
7533d3d1a6afSToby Isaac       }
7534d3d1a6afSToby Isaac     }
7535d3d1a6afSToby Isaac 
75366ecaa68aSToby Isaac     if (multiplyLeft) {
75379566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues));
75389566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices));
7539d3d1a6afSToby Isaac       /* multiply constraints transpose on the left */
7540d3d1a6afSToby Isaac       if (numFields) {
7541d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7542d3d1a6afSToby Isaac           PetscInt oldOff = offsets[f];
7543d3d1a6afSToby Isaac 
7544d3d1a6afSToby Isaac           for (p = 0; p < numPoints; p++) {
7545d3d1a6afSToby Isaac             PetscInt rStart = newPointOffsets[f][p];
7546d3d1a6afSToby Isaac             PetscInt b      = points[2 * p];
7547d3d1a6afSToby Isaac             PetscInt c, r, k;
7548d3d1a6afSToby Isaac             PetscInt dof;
7549d3d1a6afSToby Isaac 
75509566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7551d3d1a6afSToby Isaac             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7552d3d1a6afSToby Isaac               PetscInt                          nRows = newPointOffsets[f][p + 1] - rStart;
7553d3d1a6afSToby Isaac               const PetscScalar *PETSC_RESTRICT mat   = pointMat[f] + pointMatOffsets[f][p];
7554d3d1a6afSToby Isaac 
7555d3d1a6afSToby Isaac               for (r = 0; r < nRows; r++) {
7556d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7557ad540459SPierre Jolivet                   for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7558d3d1a6afSToby Isaac                 }
7559d3d1a6afSToby Isaac               }
75609371c9d4SSatish Balay             } else {
7561d3d1a6afSToby Isaac               /* copy this row as is */
7562d3d1a6afSToby Isaac               for (r = 0; r < dof; r++) {
7563ad540459SPierre Jolivet                 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7564d3d1a6afSToby Isaac               }
7565d3d1a6afSToby Isaac             }
7566d3d1a6afSToby Isaac             oldOff += dof;
7567d3d1a6afSToby Isaac           }
7568d3d1a6afSToby Isaac         }
75699371c9d4SSatish Balay       } else {
7570d3d1a6afSToby Isaac         PetscInt oldOff = 0;
7571d3d1a6afSToby Isaac 
7572d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7573d3d1a6afSToby Isaac           PetscInt rStart = newPointOffsets[0][p];
7574d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7575d3d1a6afSToby Isaac           PetscInt c, r, k;
7576d3d1a6afSToby Isaac           PetscInt dof;
7577d3d1a6afSToby Isaac 
75789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, b, &dof));
7579d3d1a6afSToby Isaac           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7580d3d1a6afSToby Isaac             PetscInt                          nRows = newPointOffsets[0][p + 1] - rStart;
7581d3d1a6afSToby Isaac             const PetscScalar *PETSC_RESTRICT mat   = pointMat[0] + pointMatOffsets[0][p];
7582d3d1a6afSToby Isaac 
7583d3d1a6afSToby Isaac             for (r = 0; r < nRows; r++) {
7584d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7585ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7586d3d1a6afSToby Isaac               }
7587d3d1a6afSToby Isaac             }
75889371c9d4SSatish Balay           } else {
7589d3d1a6afSToby Isaac             /* copy this row as is */
75909fc93327SToby Isaac             for (r = 0; r < dof; r++) {
7591ad540459SPierre Jolivet               for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7592d3d1a6afSToby Isaac             }
7593d3d1a6afSToby Isaac           }
7594d3d1a6afSToby Isaac           oldOff += dof;
7595d3d1a6afSToby Isaac         }
7596d3d1a6afSToby Isaac       }
7597d3d1a6afSToby Isaac 
75989566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
75999371c9d4SSatish Balay     } else {
76006ecaa68aSToby Isaac       newValues = tmpValues;
76016ecaa68aSToby Isaac     }
76026ecaa68aSToby Isaac   }
76036ecaa68aSToby Isaac 
7604d3d1a6afSToby Isaac   /* clean up */
76059566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices));
76069566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
76076ecaa68aSToby Isaac 
7608d3d1a6afSToby Isaac   if (numFields) {
7609d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
76109566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
76119566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
76129566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7613d3d1a6afSToby Isaac     }
76149371c9d4SSatish Balay   } else {
76159566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
76169566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
76179566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0]));
7618d3d1a6afSToby Isaac   }
76199566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
7620d3d1a6afSToby Isaac 
7621d3d1a6afSToby Isaac   /* output */
76226ecaa68aSToby Isaac   if (outPoints) {
7623d3d1a6afSToby Isaac     *outPoints = newPoints;
76249371c9d4SSatish Balay   } else {
76259566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
76266ecaa68aSToby Isaac   }
7627ad540459SPierre Jolivet   if (outValues) *outValues = newValues;
7628ad540459SPierre Jolivet   for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
76293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7630d3d1a6afSToby Isaac }
7631d3d1a6afSToby Isaac 
76324a1e0b3eSMatthew G. Knepley /*@C
763371f0bbf9SMatthew G. Knepley   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
76347cd05799SMatthew G. Knepley 
76357cd05799SMatthew G. Knepley   Not collective
76367cd05799SMatthew G. Knepley 
76377cd05799SMatthew G. Knepley   Input Parameters:
7638a1cb98faSBarry Smith + dm         - The `DM`
7639a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
7640a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
764171f0bbf9SMatthew G. Knepley . point      - The point defining the closure
764271f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
76437cd05799SMatthew G. Knepley 
764471f0bbf9SMatthew G. Knepley   Output Parameters:
764571f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
764671f0bbf9SMatthew G. Knepley . indices    - The dof indices
764720f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
764820f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
76497cd05799SMatthew G. Knepley 
7650a1cb98faSBarry Smith   Level: advanced
765136fa2b79SJed Brown 
7652a1cb98faSBarry Smith   Notes:
7653a1cb98faSBarry Smith   Must call `DMPlexRestoreClosureIndices()` to free allocated memory
7654a1cb98faSBarry Smith 
765520f4b53cSBarry Smith   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
765620f4b53cSBarry Smith   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
765736fa2b79SJed Brown   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
765820f4b53cSBarry Smith   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
765936fa2b79SJed Brown   indices (with the above semantics) are implied.
76607cd05799SMatthew G. Knepley 
76611cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
7662a1cb98faSBarry Smith           `PetscSection`, `DMGetGlobalSection()`
76634a1e0b3eSMatthew G. Knepley @*/
7664d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7665d71ae5a4SJacob Faibussowitsch {
766671f0bbf9SMatthew G. Knepley   /* Closure ordering */
76677773e69fSMatthew G. Knepley   PetscSection    clSection;
76687773e69fSMatthew G. Knepley   IS              clPoints;
766971f0bbf9SMatthew G. Knepley   const PetscInt *clp;
767071f0bbf9SMatthew G. Knepley   PetscInt       *points;
767171f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
767271f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
76734acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
767471f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
767571f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
767671f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
767771f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
767871f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
767971f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
768071f0bbf9SMatthew G. Knepley 
768171f0bbf9SMatthew G. Knepley   PetscInt *idx;
768271f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
768371f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
76847773e69fSMatthew G. Knepley 
768571f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
76867773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
76877773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
768836fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7689dadcf809SJacob Faibussowitsch   if (numIndices) PetscValidIntPointer(numIndices, 6);
769071f0bbf9SMatthew G. Knepley   if (indices) PetscValidPointer(indices, 7);
7691dadcf809SJacob Faibussowitsch   if (outOffsets) PetscValidIntPointer(outOffsets, 8);
769271f0bbf9SMatthew G. Knepley   if (values) PetscValidPointer(values, 9);
76939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
769463a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
76959566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
769671f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
769707218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7698c459fbc1SJed Brown   if (useClPerm) {
7699c459fbc1SJed Brown     PetscInt depth, clsize;
77009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7701c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
7702c459fbc1SJed Brown       PetscInt dof;
77039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7704c459fbc1SJed Brown       clsize += dof;
7705c459fbc1SJed Brown     }
77069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7707c459fbc1SJed Brown   }
770871f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
770971f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
77107773e69fSMatthew G. Knepley     PetscInt dof, fdof;
77117773e69fSMatthew G. Knepley 
77129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
77137773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
77149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
77157773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
77167773e69fSMatthew G. Knepley     }
771771f0bbf9SMatthew G. Knepley     Ni += dof;
77187773e69fSMatthew G. Knepley   }
77197773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
77201dca8a05SBarry Smith   PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni);
772171f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
772271f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
77239566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
77249566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
772571f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
772671f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
772771f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
77286ecaa68aSToby Isaac 
772971f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
773071f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
773171f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
773271f0bbf9SMatthew G. Knepley 
77339566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
77349566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
773571f0bbf9SMatthew G. Knepley         if (flip) {
773671f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
773771f0bbf9SMatthew G. Knepley 
773871f0bbf9SMatthew G. Knepley           if (!valCopy) {
77399566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
774071f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
774171f0bbf9SMatthew G. Knepley             *values = valCopy;
774271f0bbf9SMatthew G. Knepley           }
774371f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
774471f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
774571f0bbf9SMatthew G. Knepley 
774671f0bbf9SMatthew G. Knepley             for (k = 0; k < Ni; ++k) {
774771f0bbf9SMatthew G. Knepley               valCopy[Ni * (foffset + i) + k] *= fval;
774871f0bbf9SMatthew G. Knepley               valCopy[Ni * k + (foffset + i)] *= fval;
77496ecaa68aSToby Isaac             }
77506ecaa68aSToby Isaac           }
775171f0bbf9SMatthew G. Knepley         }
775271f0bbf9SMatthew G. Knepley         foffset += fdof;
775371f0bbf9SMatthew G. Knepley       }
775471f0bbf9SMatthew G. Knepley     }
775571f0bbf9SMatthew G. Knepley   }
775671f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
77579566063dSJacob Faibussowitsch   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
775871f0bbf9SMatthew G. Knepley   if (NclC) {
77599566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
776071f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
77619566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
77629566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
776371f0bbf9SMatthew G. Knepley     }
776471f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
77659566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
77669566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
776771f0bbf9SMatthew G. Knepley     }
77689566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
776971f0bbf9SMatthew G. Knepley     Ncl    = NclC;
777071f0bbf9SMatthew G. Knepley     Ni     = NiC;
777171f0bbf9SMatthew G. Knepley     points = pointsC;
777271f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
777371f0bbf9SMatthew G. Knepley   }
777471f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
77759566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
777671f0bbf9SMatthew G. Knepley   if (Nf) {
777771f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
777871f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
777971f0bbf9SMatthew G. Knepley 
77809371c9d4SSatish Balay     if (outOffsets) {
77819371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
77829371c9d4SSatish Balay     }
77839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
778471f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
778571f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
778671f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
778771f0bbf9SMatthew G. Knepley 
77889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
77897773e69fSMatthew G. Knepley       }
77907773e69fSMatthew G. Knepley     } else {
779171f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
779271f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
779371f0bbf9SMatthew G. Knepley 
77949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
779571f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
779671f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
779771f0bbf9SMatthew G. Knepley          * global section. */
77989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
779971f0bbf9SMatthew G. Knepley       }
780071f0bbf9SMatthew G. Knepley     }
780171f0bbf9SMatthew G. Knepley   } else {
780271f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
780371f0bbf9SMatthew G. Knepley 
780471f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
780571f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
78064acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
78074acb8e1eSToby Isaac 
78089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
780971f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
781071f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
78119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
78127773e69fSMatthew G. Knepley     }
78137773e69fSMatthew G. Knepley   }
781471f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
781571f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
78169566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
78179566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
78184acb8e1eSToby Isaac   }
781971f0bbf9SMatthew G. Knepley   if (NclC) {
78209566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
78217773e69fSMatthew G. Knepley   } else {
78229566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
78237773e69fSMatthew G. Knepley   }
782471f0bbf9SMatthew G. Knepley 
782571f0bbf9SMatthew G. Knepley   if (numIndices) *numIndices = Ni;
782671f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
78273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
78287773e69fSMatthew G. Knepley }
78297773e69fSMatthew G. Knepley 
78307cd05799SMatthew G. Knepley /*@C
783171f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
78327cd05799SMatthew G. Knepley 
78337cd05799SMatthew G. Knepley   Not collective
78347cd05799SMatthew G. Knepley 
78357cd05799SMatthew G. Knepley   Input Parameters:
7836a1cb98faSBarry Smith + dm         - The `DM`
7837a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
7838a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
783971f0bbf9SMatthew G. Knepley . point      - The point defining the closure
784071f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
784171f0bbf9SMatthew G. Knepley 
784271f0bbf9SMatthew G. Knepley   Output Parameters:
784371f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
784471f0bbf9SMatthew G. Knepley . indices    - The dof indices
784520f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
784620f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
784771f0bbf9SMatthew G. Knepley 
7848a1cb98faSBarry Smith   Level: advanced
784971f0bbf9SMatthew G. Knepley 
7850a1cb98faSBarry Smith   Notes:
7851a1cb98faSBarry Smith   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
7852a1cb98faSBarry Smith 
7853a1cb98faSBarry Smith   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
785471f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
785571f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
785671f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
785771f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
78587cd05799SMatthew G. Knepley 
78591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
78607cd05799SMatthew G. Knepley @*/
7861d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7862d71ae5a4SJacob Faibussowitsch {
78637773e69fSMatthew G. Knepley   PetscFunctionBegin;
78647773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7865064a246eSJacob Faibussowitsch   PetscValidPointer(indices, 7);
78669566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
78673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
78687773e69fSMatthew G. Knepley }
78697773e69fSMatthew G. Knepley 
78707f5d1fdeSMatthew G. Knepley /*@C
78717f5d1fdeSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
78727f5d1fdeSMatthew G. Knepley 
78737f5d1fdeSMatthew G. Knepley   Not collective
78747f5d1fdeSMatthew G. Knepley 
78757f5d1fdeSMatthew G. Knepley   Input Parameters:
7876a1cb98faSBarry Smith + dm - The `DM`
787720f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
787820f4b53cSBarry Smith . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
78797f5d1fdeSMatthew G. Knepley . A - The matrix
7880a1cb98faSBarry Smith . point - The point in the `DM`
78817f5d1fdeSMatthew G. Knepley . values - The array of values
7882a1cb98faSBarry Smith - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
78837f5d1fdeSMatthew G. Knepley 
78847f5d1fdeSMatthew G. Knepley   Level: intermediate
78857f5d1fdeSMatthew G. Knepley 
78861cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
78877f5d1fdeSMatthew G. Knepley @*/
7888d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7889d71ae5a4SJacob Faibussowitsch {
7890552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
7891552f7358SJed Brown   PetscInt          *indices;
789271f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
789371f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
7894552f7358SJed Brown   PetscErrorCode     ierr;
7895552f7358SJed Brown 
7896552f7358SJed Brown   PetscFunctionBegin;
7897552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
78989566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
78993dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
79009566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
79013dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
79023dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7903552f7358SJed Brown 
79049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
79050d644c17SKarl Rupp 
79069566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7907d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
79084a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7909552f7358SJed Brown   if (ierr) {
7910552f7358SJed Brown     PetscMPIInt rank;
7911552f7358SJed Brown 
79129566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
79139566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
79149566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
79159566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
79169566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7917c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
7918552f7358SJed Brown   }
79194a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
79204a1e0b3eSMatthew G. Knepley     PetscInt i;
79219566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
792263a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
79239566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
79244a1e0b3eSMatthew G. Knepley   }
792571f0bbf9SMatthew G. Knepley 
79269566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
79279566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
79283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
79294acb8e1eSToby Isaac }
793071f0bbf9SMatthew G. Knepley 
79314a1e0b3eSMatthew G. Knepley /*@C
79324a1e0b3eSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
79334a1e0b3eSMatthew G. Knepley 
79344a1e0b3eSMatthew G. Knepley   Not collective
79354a1e0b3eSMatthew G. Knepley 
79364a1e0b3eSMatthew G. Knepley   Input Parameters:
7937a1cb98faSBarry Smith + dmRow - The `DM` for the row fields
793820f4b53cSBarry Smith . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow`
793920f4b53cSBarry Smith . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
7940a1cb98faSBarry Smith . dmCol - The `DM` for the column fields
794120f4b53cSBarry Smith . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol`
794220f4b53cSBarry Smith . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
79434a1e0b3eSMatthew G. Knepley . A - The matrix
7944a1cb98faSBarry Smith . point - The point in the `DM`
79454a1e0b3eSMatthew G. Knepley . values - The array of values
7946a1cb98faSBarry Smith - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
79474a1e0b3eSMatthew G. Knepley 
79484a1e0b3eSMatthew G. Knepley   Level: intermediate
79494a1e0b3eSMatthew G. Knepley 
79501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
79514a1e0b3eSMatthew G. Knepley @*/
7952d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7953d71ae5a4SJacob Faibussowitsch {
795471f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
795571f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
795671f0bbf9SMatthew G. Knepley   PetscInt           numIndicesRow, numIndicesCol;
795771f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
795871f0bbf9SMatthew G. Knepley   PetscErrorCode     ierr;
795971f0bbf9SMatthew G. Knepley 
796071f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
796171f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
79629566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
796371f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
79649566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
796571f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
796671f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
79679566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
796871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
79699566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
797071f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
797171f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
797271f0bbf9SMatthew G. Knepley 
79739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
79749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
797571f0bbf9SMatthew G. Knepley 
79769566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7977d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
79784a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
797971f0bbf9SMatthew G. Knepley   if (ierr) {
798071f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
798171f0bbf9SMatthew G. Knepley 
79829566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
79839566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
79849566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
79859566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
79869566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values));
79879566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7988d3d1a6afSToby Isaac   }
798971f0bbf9SMatthew G. Knepley 
79909566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
79919566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
79929566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
79933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7994552f7358SJed Brown }
7995552f7358SJed Brown 
7996d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7997d71ae5a4SJacob Faibussowitsch {
7998de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
7999de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8000de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
8001de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
800217c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8003de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
8004412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
80054ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8006de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
8007de41b84cSMatthew G. Knepley 
8008de41b84cSMatthew G. Knepley   PetscFunctionBegin;
8009de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8010de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
80119566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8012de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
80139566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8014de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
80159566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8016de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
80179566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8018de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8019de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
80209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
802163a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
80229566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
80239566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
8024de41b84cSMatthew G. Knepley   /* Column indices */
80259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
80264ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
8027de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
8028de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
80299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8030de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8031de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8032de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
8033de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
8034de41b84cSMatthew G. Knepley       ++q;
8035de41b84cSMatthew G. Knepley     }
8036de41b84cSMatthew G. Knepley   }
8037de41b84cSMatthew G. Knepley   numCPoints = q;
8038de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8039de41b84cSMatthew G. Knepley     PetscInt fdof;
8040de41b84cSMatthew G. Knepley 
80419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
80424ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8043de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
80449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8045de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
8046de41b84cSMatthew G. Knepley     }
8047de41b84cSMatthew G. Knepley     numCIndices += dof;
8048de41b84cSMatthew G. Knepley   }
8049de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8050de41b84cSMatthew G. Knepley   /* Row indices */
80519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8052412e9a14SMatthew G. Knepley   {
8053012bc364SMatthew G. Knepley     DMPlexTransform tr;
8054012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8055012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8056012bc364SMatthew G. Knepley 
80579566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
80589566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
80599566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8060012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
80619566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8062412e9a14SMatthew G. Knepley   }
80639566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8064de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
8065de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
80669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8067de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
80689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8069de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
8070de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
80719566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
80724ca5e9f5SMatthew G. Knepley         if (!dof) continue;
80739371c9d4SSatish Balay         for (s = 0; s < q; ++s)
80749371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
80754ca5e9f5SMatthew G. Knepley         if (s < q) continue;
8076de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
8077de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8078de41b84cSMatthew G. Knepley         ++q;
8079de41b84cSMatthew G. Knepley       }
8080de41b84cSMatthew G. Knepley     }
80819566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8082de41b84cSMatthew G. Knepley   }
8083de41b84cSMatthew G. Knepley   numFPoints = q;
8084de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8085de41b84cSMatthew G. Knepley     PetscInt fdof;
8086de41b84cSMatthew G. Knepley 
80879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
80884ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8089de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
80909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8091de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
8092de41b84cSMatthew G. Knepley     }
8093de41b84cSMatthew G. Knepley     numFIndices += dof;
8094de41b84cSMatthew G. Knepley   }
8095de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8096de41b84cSMatthew G. Knepley 
80971dca8a05SBarry Smith   PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices);
80981dca8a05SBarry Smith   PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices);
80999566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
81009566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8101de41b84cSMatthew G. Knepley   if (numFields) {
81024acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
81034acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
81044acb8e1eSToby Isaac 
81054acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
81069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
81079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8108de41b84cSMatthew G. Knepley     }
81094acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
81109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
81119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
81124acb8e1eSToby Isaac     }
81134acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
81149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
81159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
81164acb8e1eSToby Isaac     }
81174acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
81189566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
81199566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8120de41b84cSMatthew G. Knepley     }
8121de41b84cSMatthew G. Knepley   } else {
81224acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
81234acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
81244acb8e1eSToby Isaac 
81259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
81269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
81274acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
81284acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
81294acb8e1eSToby Isaac 
81309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
81319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8132de41b84cSMatthew G. Knepley     }
81334acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
81344acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
81354acb8e1eSToby Isaac 
81369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
81379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8138de41b84cSMatthew G. Knepley     }
81399566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
81409566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8141de41b84cSMatthew G. Knepley   }
81429566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
81434acb8e1eSToby Isaac   /* TODO: flips */
8144d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8145de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8146de41b84cSMatthew G. Knepley   if (ierr) {
8147de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8148de41b84cSMatthew G. Knepley 
81499566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
81509566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
81519566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
81529566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
81539566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8154de41b84cSMatthew G. Knepley   }
81559566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
81569566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
81579566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
81589566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
81593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8160de41b84cSMatthew G. Knepley }
8161de41b84cSMatthew G. Knepley 
8162d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8163d71ae5a4SJacob Faibussowitsch {
81647c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
81657c927364SMatthew G. Knepley   PetscInt       *cpoints = NULL;
81667c927364SMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
816717c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8168412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
81697c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
81707c927364SMatthew G. Knepley 
81717c927364SMatthew G. Knepley   PetscFunctionBegin;
81727c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
81737c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
81749566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
81757c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
81769566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
81777c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
81789566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
81797c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
81809566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
81817c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
81829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
818363a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
81849566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
81859566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
81867c927364SMatthew G. Knepley   /* Column indices */
81879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
81887c927364SMatthew G. Knepley   maxFPoints = numCPoints;
81897c927364SMatthew G. Knepley   /* Compress out points not in the section */
81907c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
81919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
81927c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
81937c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
81947c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
81957c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
81967c927364SMatthew G. Knepley       ++q;
81977c927364SMatthew G. Knepley     }
81987c927364SMatthew G. Knepley   }
81997c927364SMatthew G. Knepley   numCPoints = q;
82007c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
82017c927364SMatthew G. Knepley     PetscInt fdof;
82027c927364SMatthew G. Knepley 
82039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
82047c927364SMatthew G. Knepley     if (!dof) continue;
82057c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
82069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
82077c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
82087c927364SMatthew G. Knepley     }
82097c927364SMatthew G. Knepley     numCIndices += dof;
82107c927364SMatthew G. Knepley   }
82117c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
82127c927364SMatthew G. Knepley   /* Row indices */
82139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8214412e9a14SMatthew G. Knepley   {
8215012bc364SMatthew G. Knepley     DMPlexTransform tr;
8216012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8217012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8218012bc364SMatthew G. Knepley 
82199566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
82209566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
82219566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8222012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
82239566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8224412e9a14SMatthew G. Knepley   }
82259566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
82267c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
82277c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
82289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
82297c927364SMatthew G. Knepley     /* Compress out points not in the section */
82309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
82317c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
82327c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
82339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
82347c927364SMatthew G. Knepley         if (!dof) continue;
82359371c9d4SSatish Balay         for (s = 0; s < q; ++s)
82369371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
82377c927364SMatthew G. Knepley         if (s < q) continue;
82387c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
82397c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
82407c927364SMatthew G. Knepley         ++q;
82417c927364SMatthew G. Knepley       }
82427c927364SMatthew G. Knepley     }
82439566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
82447c927364SMatthew G. Knepley   }
82457c927364SMatthew G. Knepley   numFPoints = q;
82467c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
82477c927364SMatthew G. Knepley     PetscInt fdof;
82487c927364SMatthew G. Knepley 
82499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
82507c927364SMatthew G. Knepley     if (!dof) continue;
82517c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
82529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
82537c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
82547c927364SMatthew G. Knepley     }
82557c927364SMatthew G. Knepley     numFIndices += dof;
82567c927364SMatthew G. Knepley   }
82577c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
82587c927364SMatthew G. Knepley 
82591dca8a05SBarry Smith   PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices);
82601dca8a05SBarry Smith   PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices);
82617c927364SMatthew G. Knepley   if (numFields) {
82624acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
82634acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
82644acb8e1eSToby Isaac 
82654acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
82669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
82679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
82687c927364SMatthew G. Knepley     }
82694acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
82709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
82719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
82724acb8e1eSToby Isaac     }
82734acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
82749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
82759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
82764acb8e1eSToby Isaac     }
82774acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
82789566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
82799566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
82807c927364SMatthew G. Knepley     }
82817c927364SMatthew G. Knepley   } else {
82824acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
82834acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
82844acb8e1eSToby Isaac 
82859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
82869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
82874acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
82884acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
82894acb8e1eSToby Isaac 
82909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
82919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
82927c927364SMatthew G. Knepley     }
82934acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
82944acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
82954acb8e1eSToby Isaac 
82969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
82979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
82987c927364SMatthew G. Knepley     }
82999566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
83009566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
83017c927364SMatthew G. Knepley   }
83029566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
83039566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
83043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83057c927364SMatthew G. Knepley }
83067c927364SMatthew G. Knepley 
83077cd05799SMatthew G. Knepley /*@C
83087cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
83097cd05799SMatthew G. Knepley 
83107cd05799SMatthew G. Knepley   Input Parameter:
8311a1cb98faSBarry Smith . dm   - The `DMPLEX` object
83127cd05799SMatthew G. Knepley 
83137cd05799SMatthew G. Knepley   Output Parameter:
83147cd05799SMatthew G. Knepley . cellHeight - The height of a cell
83157cd05799SMatthew G. Knepley 
83167cd05799SMatthew G. Knepley   Level: developer
83177cd05799SMatthew G. Knepley 
83181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
83197cd05799SMatthew G. Knepley @*/
8320d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8321d71ae5a4SJacob Faibussowitsch {
8322552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8323552f7358SJed Brown 
8324552f7358SJed Brown   PetscFunctionBegin;
8325552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8326dadcf809SJacob Faibussowitsch   PetscValidIntPointer(cellHeight, 2);
8327552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
83283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8329552f7358SJed Brown }
8330552f7358SJed Brown 
83317cd05799SMatthew G. Knepley /*@C
83327cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
83337cd05799SMatthew G. Knepley 
83347cd05799SMatthew G. Knepley   Input Parameters:
8335a1cb98faSBarry Smith + dm   - The `DMPLEX` object
83367cd05799SMatthew G. Knepley - cellHeight - The height of a cell
83377cd05799SMatthew G. Knepley 
83387cd05799SMatthew G. Knepley   Level: developer
83397cd05799SMatthew G. Knepley 
83401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
83417cd05799SMatthew G. Knepley @*/
8342d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8343d71ae5a4SJacob Faibussowitsch {
8344552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8345552f7358SJed Brown 
8346552f7358SJed Brown   PetscFunctionBegin;
8347552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8348552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
83493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8350552f7358SJed Brown }
8351552f7358SJed Brown 
8352e6139122SMatthew G. Knepley /*@
83532827ebadSStefano Zampini   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8354e6139122SMatthew G. Knepley 
83552827ebadSStefano Zampini   Input Parameters:
83562827ebadSStefano Zampini + dm - The `DMPLEX` object
83572827ebadSStefano Zampini - ct - The `DMPolytopeType` of the cell
8358e6139122SMatthew G. Knepley 
8359e6139122SMatthew G. Knepley   Output Parameters:
83602827ebadSStefano Zampini + start - The first cell of this type, or `NULL`
83612827ebadSStefano Zampini - end   - The upper bound on this celltype, or `NULL`
8362e6139122SMatthew G. Knepley 
83632a9f31c0SMatthew G. Knepley   Level: advanced
8364e6139122SMatthew G. Knepley 
83652827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8366e6139122SMatthew G. Knepley @*/
83672827ebadSStefano Zampini PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end)
8368d71ae5a4SJacob Faibussowitsch {
83692827ebadSStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
83702827ebadSStefano Zampini   DMLabel  label;
83712827ebadSStefano Zampini   PetscInt pStart, pEnd;
8372e6139122SMatthew G. Knepley 
8373e6139122SMatthew G. Knepley   PetscFunctionBegin;
8374e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
83752827ebadSStefano Zampini   if (start) {
83762827ebadSStefano Zampini     PetscValidIntPointer(start, 3);
83772827ebadSStefano Zampini     *start = 0;
83782827ebadSStefano Zampini   }
83792827ebadSStefano Zampini   if (end) {
83802827ebadSStefano Zampini     PetscValidIntPointer(end, 4);
83812827ebadSStefano Zampini     *end = 0;
83822827ebadSStefano Zampini   }
83832827ebadSStefano Zampini   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
83842827ebadSStefano Zampini   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
83852827ebadSStefano Zampini   if (mesh->tr) {
83862827ebadSStefano Zampini     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
83872827ebadSStefano Zampini   } else {
83882827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
83892827ebadSStefano Zampini     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
83902827ebadSStefano Zampini     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
83912827ebadSStefano Zampini   }
83923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8393e6139122SMatthew G. Knepley }
8394e6139122SMatthew G. Knepley 
8395d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8396d71ae5a4SJacob Faibussowitsch {
8397552f7358SJed Brown   PetscSection section, globalSection;
8398552f7358SJed Brown   PetscInt    *numbers, p;
8399552f7358SJed Brown 
8400552f7358SJed Brown   PetscFunctionBegin;
8401d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
84029566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
84039566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
840448a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
84059566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
84069566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
84079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8408552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
84099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8410ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
8411ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
8412552f7358SJed Brown   }
84139566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8414ef48cebcSMatthew G. Knepley   if (globalSize) {
8415ef48cebcSMatthew G. Knepley     PetscLayout layout;
84169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
84179566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
84189566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8419ef48cebcSMatthew G. Knepley   }
84209566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
84219566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
84223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8423552f7358SJed Brown }
8424552f7358SJed Brown 
8425d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8426d71ae5a4SJacob Faibussowitsch {
8427412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
8428552f7358SJed Brown 
8429552f7358SJed Brown   PetscFunctionBegin;
84309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
84319566063dSJacob Faibussowitsch   if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
84329566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
84339566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
84343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8435552f7358SJed Brown }
843681ed3555SMatthew G. Knepley 
84378dab3259SMatthew G. Knepley /*@
84387cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
84397cd05799SMatthew G. Knepley 
84407cd05799SMatthew G. Knepley   Input Parameter:
8441a1cb98faSBarry Smith . dm   - The `DMPLEX` object
84427cd05799SMatthew G. Knepley 
84437cd05799SMatthew G. Knepley   Output Parameter:
84447cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
84457cd05799SMatthew G. Knepley 
84467cd05799SMatthew G. Knepley   Level: developer
84477cd05799SMatthew G. Knepley 
84481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()`
84497cd05799SMatthew G. Knepley @*/
8450d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8451d71ae5a4SJacob Faibussowitsch {
845281ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
845381ed3555SMatthew G. Knepley 
845481ed3555SMatthew G. Knepley   PetscFunctionBegin;
845581ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84569566063dSJacob Faibussowitsch   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8457552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
84583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8459552f7358SJed Brown }
8460552f7358SJed Brown 
8461d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8462d71ae5a4SJacob Faibussowitsch {
8463412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
846481ed3555SMatthew G. Knepley 
846581ed3555SMatthew G. Knepley   PetscFunctionBegin;
846681ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
84689566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
84693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
847081ed3555SMatthew G. Knepley }
847181ed3555SMatthew G. Knepley 
84728dab3259SMatthew G. Knepley /*@
84736aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
84747cd05799SMatthew G. Knepley 
84757cd05799SMatthew G. Knepley   Input Parameter:
8476a1cb98faSBarry Smith . dm   - The `DMPLEX` object
84777cd05799SMatthew G. Knepley 
84787cd05799SMatthew G. Knepley   Output Parameter:
84797cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
84807cd05799SMatthew G. Knepley 
84817cd05799SMatthew G. Knepley   Level: developer
84827cd05799SMatthew G. Knepley 
84831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
84847cd05799SMatthew G. Knepley @*/
8485d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8486d71ae5a4SJacob Faibussowitsch {
8487552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8488552f7358SJed Brown 
8489552f7358SJed Brown   PetscFunctionBegin;
8490552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84919566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8492552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
84933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8494552f7358SJed Brown }
8495552f7358SJed Brown 
84968dab3259SMatthew G. Knepley /*@
8497966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
8498966484cfSJed Brown 
849920f4b53cSBarry Smith   Collective
85007cd05799SMatthew G. Knepley 
85017cd05799SMatthew G. Knepley   Input Parameter:
8502a1cb98faSBarry Smith . dm   - The `DMPLEX` object
85037cd05799SMatthew G. Knepley 
85047cd05799SMatthew G. Knepley   Output Parameter:
85057cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
85067cd05799SMatthew G. Knepley 
8507a1cb98faSBarry Smith   Level: developer
8508966484cfSJed Brown 
8509a1cb98faSBarry Smith   Notes:
8510a1cb98faSBarry Smith   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
8511966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
8512966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
8513966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
8514966484cfSJed Brown 
8515966484cfSJed Brown   The partitioned mesh is
8516966484cfSJed Brown ```
8517966484cfSJed Brown  (2)--0--(3)--1--(4)    (1)--0--(2)
8518966484cfSJed Brown ```
8519966484cfSJed Brown   and its global numbering is
8520966484cfSJed Brown ```
8521966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
8522966484cfSJed Brown ```
8523966484cfSJed Brown   Then the global numbering is provided as
8524966484cfSJed Brown ```
8525966484cfSJed Brown [0] Number of indices in set 5
8526966484cfSJed Brown [0] 0 0
8527966484cfSJed Brown [0] 1 1
8528966484cfSJed Brown [0] 2 3
8529966484cfSJed Brown [0] 3 4
8530966484cfSJed Brown [0] 4 -6
8531966484cfSJed Brown [1] Number of indices in set 3
8532966484cfSJed Brown [1] 0 2
8533966484cfSJed Brown [1] 1 5
8534966484cfSJed Brown [1] 2 6
8535966484cfSJed Brown ```
8536966484cfSJed Brown 
85371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
85387cd05799SMatthew G. Knepley @*/
8539d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8540d71ae5a4SJacob Faibussowitsch {
8541ef48cebcSMatthew G. Knepley   IS        nums[4];
8542862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
8543ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
85440c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
8545ef48cebcSMatthew G. Knepley 
8546ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8547ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
85489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
85490c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
85509566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
85510c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
8552862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8553862913ffSStefano Zampini     PetscInt end;
8554862913ffSStefano Zampini 
8555862913ffSStefano Zampini     depths[d] = depth - d;
85569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
85570c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
8558862913ffSStefano Zampini   }
85590c15888dSMatthew G. Knepley   if (empty)
85600c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
85610c15888dSMatthew G. Knepley       depths[d] = -1;
85620c15888dSMatthew G. Knepley       starts[d] = -1;
85630c15888dSMatthew G. Knepley     }
85640c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
85651c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
8566ad540459SPierre Jolivet   for (d = 0; d <= depth; ++d) PetscCheck(starts[d] < 0 || depths[d] == gdepths[d], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT, depths[d], gdepths[d]);
85670c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
8568ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8569ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8570ef48cebcSMatthew G. Knepley 
85719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
85729566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8573ef48cebcSMatthew G. Knepley     shift += gsize;
8574ef48cebcSMatthew G. Knepley   }
8575d1c35871SJed Brown   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
85769566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
85773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8578ef48cebcSMatthew G. Knepley }
8579ef48cebcSMatthew G. Knepley 
858008a22f4bSMatthew G. Knepley /*@
858108a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
858208a22f4bSMatthew G. Knepley 
858308a22f4bSMatthew G. Knepley   Input Parameter:
8584a1cb98faSBarry Smith . dm - The `DMPLEX` object
858508a22f4bSMatthew G. Knepley 
858608a22f4bSMatthew G. Knepley   Output Parameter:
858708a22f4bSMatthew G. Knepley . ranks - The rank field
858808a22f4bSMatthew G. Knepley 
8589a1cb98faSBarry Smith   Options Database Key:
859020f4b53cSBarry Smith . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
859108a22f4bSMatthew G. Knepley 
859208a22f4bSMatthew G. Knepley   Level: intermediate
859308a22f4bSMatthew G. Knepley 
85941cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
859508a22f4bSMatthew G. Knepley @*/
8596d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8597d71ae5a4SJacob Faibussowitsch {
859808a22f4bSMatthew G. Knepley   DM             rdm;
859908a22f4bSMatthew G. Knepley   PetscFE        fe;
860008a22f4bSMatthew G. Knepley   PetscScalar   *r;
860108a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
8602a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
860308a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
8604a55f9a55SMatthew G. Knepley   PetscBool      simplex;
860508a22f4bSMatthew G. Knepley 
860608a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
8607f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8608f95ace6aSMatthew G. Knepley   PetscValidPointer(ranks, 2);
86099566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
86109566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
86119566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
86129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
86139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8614a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
86159566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
86169566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
86179566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
86189566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
86199566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
86209566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
86219566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
86229566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
862308a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
862408a22f4bSMatthew G. Knepley     PetscScalar *lr;
862508a22f4bSMatthew G. Knepley 
86269566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
862771f09efeSPierre Jolivet     if (lr) *lr = rank;
862808a22f4bSMatthew G. Knepley   }
86299566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
86309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
86313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
863208a22f4bSMatthew G. Knepley }
863308a22f4bSMatthew G. Knepley 
8634ca8062c8SMatthew G. Knepley /*@
863518e14f0cSMatthew G. Knepley   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
863618e14f0cSMatthew G. Knepley 
863718e14f0cSMatthew G. Knepley   Input Parameters:
863820f4b53cSBarry Smith + dm    - The `DMPLEX`
863920f4b53cSBarry Smith - label - The `DMLabel`
864018e14f0cSMatthew G. Knepley 
864118e14f0cSMatthew G. Knepley   Output Parameter:
864218e14f0cSMatthew G. Knepley . val - The label value field
864318e14f0cSMatthew G. Knepley 
864420f4b53cSBarry Smith   Options Database Key:
864520f4b53cSBarry Smith . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
864618e14f0cSMatthew G. Knepley 
864718e14f0cSMatthew G. Knepley   Level: intermediate
864818e14f0cSMatthew G. Knepley 
86491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
865018e14f0cSMatthew G. Knepley @*/
8651d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8652d71ae5a4SJacob Faibussowitsch {
865318e14f0cSMatthew G. Knepley   DM           rdm;
865418e14f0cSMatthew G. Knepley   PetscFE      fe;
865518e14f0cSMatthew G. Knepley   PetscScalar *v;
865618e14f0cSMatthew G. Knepley   PetscInt     dim, cStart, cEnd, c;
865718e14f0cSMatthew G. Knepley 
865818e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
865918e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
866018e14f0cSMatthew G. Knepley   PetscValidPointer(label, 2);
866118e14f0cSMatthew G. Knepley   PetscValidPointer(val, 3);
86629566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
86639566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
86649566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
86659566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "label_value"));
86669566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
86679566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
86689566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
86699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
86709566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
86719566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*val, "label_value"));
86729566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*val, &v));
867318e14f0cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
867418e14f0cSMatthew G. Knepley     PetscScalar *lv;
867518e14f0cSMatthew G. Knepley     PetscInt     cval;
867618e14f0cSMatthew G. Knepley 
86779566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv));
86789566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, c, &cval));
867918e14f0cSMatthew G. Knepley     *lv = cval;
868018e14f0cSMatthew G. Knepley   }
86819566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*val, &v));
86829566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
86833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
868418e14f0cSMatthew G. Knepley }
868518e14f0cSMatthew G. Knepley 
868618e14f0cSMatthew G. Knepley /*@
8687ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8688ca8062c8SMatthew G. Knepley 
868969916449SMatthew G. Knepley   Input Parameter:
8690a1cb98faSBarry Smith . dm - The `DMPLEX` object
8691a1cb98faSBarry Smith 
8692a1cb98faSBarry Smith   Level: developer
8693ca8062c8SMatthew G. Knepley 
869495eb5ee5SVaclav Hapla   Notes:
869595eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
869695eb5ee5SVaclav Hapla 
869720f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
8698ca8062c8SMatthew G. Knepley 
86991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
8700ca8062c8SMatthew G. Knepley @*/
8701d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
8702d71ae5a4SJacob Faibussowitsch {
8703ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
8704ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
8705ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
870657beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
870757beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
8708ca8062c8SMatthew G. Knepley 
8709ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8710ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87119566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
87129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
87139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
8714ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
87159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8716ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
87179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
87189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
8719ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
872042e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
872142e66dfaSMatthew G. Knepley       PetscInt  d;
872242e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
87239371c9d4SSatish Balay         if (cone[c] == cone[d]) {
87249371c9d4SSatish Balay           dup = PETSC_TRUE;
87259371c9d4SSatish Balay           break;
87269371c9d4SSatish Balay         }
872742e66dfaSMatthew G. Knepley       }
87289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
87299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
8730ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
8731ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
8732ca8062c8SMatthew G. Knepley       }
873342e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
873463a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
873548a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
87369566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
873763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
873848a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
87399566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
874063a3b9bcSJacob Faibussowitsch         PetscCheck(!dup, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not repeatedly found in support of repeated cone point %" PetscInt_FMT, p, cone[c]);
8741f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
8742ca8062c8SMatthew G. Knepley       }
874342e66dfaSMatthew G. Knepley     }
87449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
87459371c9d4SSatish Balay     if (p != pp) {
87469371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
87479371c9d4SSatish Balay       continue;
87489371c9d4SSatish Balay     }
87499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
87509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
8751ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
87529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
87539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
8754ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
87559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
87569371c9d4SSatish Balay         if (cone[c] != pp) {
87579371c9d4SSatish Balay           c = 0;
87589371c9d4SSatish Balay           break;
87599371c9d4SSatish Balay         }
8760ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
8761ca8062c8SMatthew G. Knepley       }
8762ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
876363a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
876448a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
87659566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
876663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
876748a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
87689566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
876963a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
8770ca8062c8SMatthew G. Knepley       }
8771ca8062c8SMatthew G. Knepley     }
8772ca8062c8SMatthew G. Knepley   }
877357beb4faSStefano Zampini   if (storagecheck) {
87749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
87759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
877663a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
877757beb4faSStefano Zampini   }
87783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8779ca8062c8SMatthew G. Knepley }
8780ca8062c8SMatthew G. Knepley 
8781412e9a14SMatthew G. Knepley /*
8782412e9a14SMatthew G. Knepley   For submeshes with cohesive cells (see DMPlexConstructCohesiveCells()), we allow a special case where some of the boundary of a face (edges and vertices) are not duplicated. We call these special boundary points "unsplit", since the same edge or vertex appears in both copies of the face. These unsplit points throw off our counting, so we have to explicitly account for them here.
8783412e9a14SMatthew G. Knepley */
8784d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8785d71ae5a4SJacob Faibussowitsch {
8786412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
8787412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
8788412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
8789412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8790412e9a14SMatthew G. Knepley 
8791412e9a14SMatthew G. Knepley   PetscFunctionBegin;
8792412e9a14SMatthew G. Knepley   *unsplit = 0;
8793412e9a14SMatthew G. Knepley   switch (ct) {
8794d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
8795d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
8796d71ae5a4SJacob Faibussowitsch     break;
8797412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
87989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
87999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8800412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
88019566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
8802412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8803412e9a14SMatthew G. Knepley     }
8804412e9a14SMatthew G. Knepley     break;
8805412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
8806412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
88079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
88089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8809412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
88109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
88119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
8812412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
88139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
8814412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8815412e9a14SMatthew G. Knepley           PetscInt p;
88169371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
88179371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
8818412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
8819412e9a14SMatthew G. Knepley         }
8820412e9a14SMatthew G. Knepley       }
8821412e9a14SMatthew G. Knepley     }
8822412e9a14SMatthew G. Knepley     break;
8823d71ae5a4SJacob Faibussowitsch   default:
8824d71ae5a4SJacob Faibussowitsch     break;
8825412e9a14SMatthew G. Knepley   }
8826412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
88279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
8828412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8829412e9a14SMatthew G. Knepley   }
88303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8831412e9a14SMatthew G. Knepley }
8832412e9a14SMatthew G. Knepley 
8833ca8062c8SMatthew G. Knepley /*@
8834ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8835ca8062c8SMatthew G. Knepley 
8836ca8062c8SMatthew G. Knepley   Input Parameters:
8837a1cb98faSBarry Smith + dm - The `DMPLEX` object
883858723a97SMatthew G. Knepley - cellHeight - Normally 0
8839ca8062c8SMatthew G. Knepley 
8840a1cb98faSBarry Smith   Level: developer
8841a1cb98faSBarry Smith 
884295eb5ee5SVaclav Hapla   Notes:
884395eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
884425c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
8845ca8062c8SMatthew G. Knepley 
884620f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
884795eb5ee5SVaclav Hapla 
88481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
8849ca8062c8SMatthew G. Knepley @*/
8850d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8851d71ae5a4SJacob Faibussowitsch {
8852412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
8853412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
8854412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
8855ca8062c8SMatthew G. Knepley 
8856ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8857ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88589566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
88599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
88609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8861412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8862412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
8863412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
886458723a97SMatthew G. Knepley 
88659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
886663a3b9bcSJacob Faibussowitsch     PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c);
8867412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8868412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
88699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
887063a3b9bcSJacob Faibussowitsch       PetscCheck(coneSize == DMPolytopeTypeGetConeSize(ct), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has cone size %" PetscInt_FMT " != %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct));
8871412e9a14SMatthew G. Knepley     }
88729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
887358723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
887458723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
8875412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
887658723a97SMatthew G. Knepley     }
88779566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8878412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
8879412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8880412e9a14SMatthew G. Knepley       PetscInt unsplit;
888142363296SMatthew G. Knepley 
88829566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8883412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
888442363296SMatthew G. Knepley     }
888563a3b9bcSJacob Faibussowitsch     PetscCheck(Nv == DMPolytopeTypeGetNumVertices(ct), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices != %" PetscInt_FMT, c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct));
888642363296SMatthew G. Knepley   }
88873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8888ca8062c8SMatthew G. Knepley }
88899bf0dad6SMatthew G. Knepley 
88909bf0dad6SMatthew G. Knepley /*@
88919bf0dad6SMatthew G. Knepley   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
88929bf0dad6SMatthew G. Knepley 
889320f4b53cSBarry Smith   Collective
8894899ea2b8SJacob Faibussowitsch 
88959bf0dad6SMatthew G. Knepley   Input Parameters:
8896a1cb98faSBarry Smith + dm - The `DMPLEX` object
88979bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
88989bf0dad6SMatthew G. Knepley 
8899a1cb98faSBarry Smith   Level: developer
8900a1cb98faSBarry Smith 
890145da879fSVaclav Hapla   Notes:
890245da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
890345da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
890445da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
890545da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
89069bf0dad6SMatthew G. Knepley 
8907a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
890895eb5ee5SVaclav Hapla 
89091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
89109bf0dad6SMatthew G. Knepley @*/
8911d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8912d71ae5a4SJacob Faibussowitsch {
8913ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8914899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
89159bf0dad6SMatthew G. Knepley 
89169bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
89179bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89188f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
89193ba16761SJacob Faibussowitsch   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
89208f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
89213ba16761SJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
89223ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
8923899ea2b8SJacob Faibussowitsch   }
8924899ea2b8SJacob Faibussowitsch 
89259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
89269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
89279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8928ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
89299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
89303554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
8931412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
8932412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
8933ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
8934412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
8935412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
89369bf0dad6SMatthew G. Knepley 
89379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
89389566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8939412e9a14SMatthew G. Knepley       if (unsplit) continue;
89409566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
89419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
89429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
89439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
89449bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
89459bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
89469bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
89479bf0dad6SMatthew G. Knepley       }
89489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
894963a3b9bcSJacob Faibussowitsch       PetscCheck(coneSize == numFaces, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " faces but should have %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, numFaces);
89509bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
8951d4961f80SStefano Zampini         DMPolytopeType fct;
89529bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
89539bf0dad6SMatthew G. Knepley 
89549566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
89559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
89569bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
89579bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
89589bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
89599bf0dad6SMatthew G. Knepley         }
896063a3b9bcSJacob Faibussowitsch         PetscCheck(fnumCorners == faceSizes[f], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices but should have %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, c, DMPolytopeTypes[ct], fnumCorners, faceSizes[f]);
89619bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
8962b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
8963b5a892a1SMatthew G. Knepley             PetscInt v1;
8964b5a892a1SMatthew G. Knepley 
89659566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
896663a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
89679566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
896863a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
89699566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
897063a3b9bcSJacob Faibussowitsch             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ", ornt %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s vertex %" PetscInt_FMT ", %" PetscInt_FMT " != %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff + v]);
8971b5a892a1SMatthew G. Knepley           }
89729bf0dad6SMatthew G. Knepley         }
89739566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
8974412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
89759bf0dad6SMatthew G. Knepley       }
89769566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
89779566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
89789bf0dad6SMatthew G. Knepley     }
89793554e41dSMatthew G. Knepley   }
89803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8981552f7358SJed Brown }
89823913d7c8SMatthew G. Knepley 
8983bb6a34a8SMatthew G. Knepley /*@
8984bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
8985bb6a34a8SMatthew G. Knepley 
8986bb6a34a8SMatthew G. Knepley   Input Parameter:
8987a1cb98faSBarry Smith . dm - The `DMPLEX` object
8988a1cb98faSBarry Smith 
8989a1cb98faSBarry Smith   Level: developer
8990bb6a34a8SMatthew G. Knepley 
899195eb5ee5SVaclav Hapla   Notes:
899295eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
899395eb5ee5SVaclav Hapla 
899420f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
8995bb6a34a8SMatthew G. Knepley 
89961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
8997bb6a34a8SMatthew G. Knepley @*/
8998d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
8999d71ae5a4SJacob Faibussowitsch {
9000a2a9e04cSMatthew G. Knepley   Vec       coordinates;
9001bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
9002bb6a34a8SMatthew G. Knepley   PetscReal vol;
900351a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9004bb6a34a8SMatthew G. Knepley 
9005bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
90069566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
90079566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
90083ba16761SJacob Faibussowitsch   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
90099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
9010bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
90119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9012a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
90139566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
90143ba16761SJacob Faibussowitsch   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9015412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9016412e9a14SMatthew G. Knepley     DMPolytopeType ct;
9017412e9a14SMatthew G. Knepley     PetscInt       unsplit;
9018412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
9019412e9a14SMatthew G. Knepley 
90209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9021412e9a14SMatthew G. Knepley     switch (ct) {
9022412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9023412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9024d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9025d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
9026d71ae5a4SJacob Faibussowitsch       break;
9027d71ae5a4SJacob Faibussowitsch     default:
9028d71ae5a4SJacob Faibussowitsch       break;
9029412e9a14SMatthew G. Knepley     }
9030412e9a14SMatthew G. Knepley     switch (ct) {
9031412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
9032412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9033412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9034d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
9035d71ae5a4SJacob Faibussowitsch       continue;
9036d71ae5a4SJacob Faibussowitsch     default:
9037d71ae5a4SJacob Faibussowitsch       break;
9038412e9a14SMatthew G. Knepley     }
90399566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9040412e9a14SMatthew G. Knepley     if (unsplit) continue;
90419566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
90421dca8a05SBarry Smith     PetscCheck(detJ >= -PETSC_SMALL && (detJ > 0.0 || ignoreZeroVol), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double)detJ);
904363a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
90446858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
90456858538eSMatthew G. Knepley     if (depth > 1) {
90469566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
90471dca8a05SBarry Smith       PetscCheck(vol >= -PETSC_SMALL && (vol > 0.0 || ignoreZeroVol), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double)vol);
904863a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9049bb6a34a8SMatthew G. Knepley     }
9050bb6a34a8SMatthew G. Knepley   }
90513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9052bb6a34a8SMatthew G. Knepley }
9053bb6a34a8SMatthew G. Knepley 
905403da9461SVaclav Hapla /*@
905520f4b53cSBarry Smith   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
90567726db96SVaclav Hapla 
905720f4b53cSBarry Smith   Collective
905803da9461SVaclav Hapla 
905903da9461SVaclav Hapla   Input Parameters:
9060a1cb98faSBarry Smith + dm - The `DMPLEX` object
906120f4b53cSBarry Smith . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9062a1cb98faSBarry Smith - allowExtraRoots - Flag to allow extra points not present in the `DM`
9063a1cb98faSBarry Smith 
9064a1cb98faSBarry Smith   Level: developer
906503da9461SVaclav Hapla 
9066e83a0d2dSVaclav Hapla   Notes:
9067e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
906803da9461SVaclav Hapla 
9069a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
907095eb5ee5SVaclav Hapla 
9071d7d32a9aSMatthew G. Knepley   Extra roots can come from priodic cuts, where additional points appear on the boundary
9072d7d32a9aSMatthew G. Knepley 
90731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
907403da9461SVaclav Hapla @*/
9075d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9076d71ae5a4SJacob Faibussowitsch {
90777726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
90787726db96SVaclav Hapla   const PetscInt    *locals;
90797726db96SVaclav Hapla   const PetscSFNode *remotes;
9080f0cfc026SVaclav Hapla   PetscBool          distributed;
90817726db96SVaclav Hapla   MPI_Comm           comm;
90827726db96SVaclav Hapla   PetscMPIInt        rank;
908303da9461SVaclav Hapla 
908403da9461SVaclav Hapla   PetscFunctionBegin;
908503da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90867726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
90877726db96SVaclav Hapla   else pointSF = dm->sf;
90887726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
90897726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
90907726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
90917726db96SVaclav Hapla   {
90927726db96SVaclav Hapla     PetscMPIInt mpiFlag;
90937726db96SVaclav Hapla 
90947726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
90957726db96SVaclav Hapla     PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag);
90967726db96SVaclav Hapla   }
90977726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
90989566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
90997726db96SVaclav Hapla   if (!distributed) {
91007726db96SVaclav Hapla     PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves);
91013ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
91028918e3e2SVaclav Hapla   }
91037726db96SVaclav Hapla   PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves);
91047726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
910503da9461SVaclav Hapla 
91067726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
91077726db96SVaclav Hapla   {
91087726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
91097726db96SVaclav Hapla 
91107726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
91117726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9112d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
91137726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
91147726db96SVaclav Hapla   }
91157726db96SVaclav Hapla 
91167726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
91177726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
91187726db96SVaclav Hapla     PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index);
91197726db96SVaclav Hapla   }
91207726db96SVaclav Hapla 
91217726db96SVaclav Hapla   /* Check there are no cells in interface */
91227726db96SVaclav Hapla   if (!overlap) {
91237726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
91247726db96SVaclav Hapla 
91259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
91269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9127f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
91287726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
9129f5869d18SMatthew G. Knepley 
91307726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
91317726db96SVaclav Hapla     }
913203da9461SVaclav Hapla   }
9133ece87651SVaclav Hapla 
91347726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
91357726db96SVaclav Hapla   {
91367726db96SVaclav Hapla     const PetscInt *rootdegree;
91377726db96SVaclav Hapla 
91387726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
91397726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9140f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
91417726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9142f5869d18SMatthew G. Knepley       const PetscInt *cone;
9143f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9144f5869d18SMatthew G. Knepley 
91459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
91469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9147f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9148f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
91497726db96SVaclav Hapla           if (locals) {
91509566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
91517726db96SVaclav Hapla           } else {
91527726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
91537726db96SVaclav Hapla           }
915463a3b9bcSJacob Faibussowitsch           PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]);
9155f5869d18SMatthew G. Knepley         }
9156f5869d18SMatthew G. Knepley       }
9157ece87651SVaclav Hapla     }
91587726db96SVaclav Hapla   }
91593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
916003da9461SVaclav Hapla }
916103da9461SVaclav Hapla 
91627f9d8d6cSVaclav Hapla /*@
916320f4b53cSBarry Smith   DMPlexCheck - Perform various checks of `DMPLEX` sanity
91647f9d8d6cSVaclav Hapla 
91657f9d8d6cSVaclav Hapla   Input Parameter:
9166a1cb98faSBarry Smith . dm - The `DMPLEX` object
9167a1cb98faSBarry Smith 
9168a1cb98faSBarry Smith   Level: developer
91697f9d8d6cSVaclav Hapla 
91707f9d8d6cSVaclav Hapla   Notes:
91717f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
91727f9d8d6cSVaclav Hapla 
917320f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
91747f9d8d6cSVaclav Hapla 
917520f4b53cSBarry Smith   Currently does not include `DMPlexCheckCellShape()`.
91767f9d8d6cSVaclav Hapla 
91771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
91787f9d8d6cSVaclav Hapla @*/
9179d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9180d71ae5a4SJacob Faibussowitsch {
91817f9d8d6cSVaclav Hapla   PetscInt cellHeight;
91827f9d8d6cSVaclav Hapla 
9183b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
91847f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
91859566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
91869566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
91879566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
91889566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9189d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
91909566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
91913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9192b5a892a1SMatthew G. Knepley }
9193b5a892a1SMatthew G. Knepley 
91949371c9d4SSatish Balay typedef struct cell_stats {
9195068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9196068a5610SStefano Zampini   PetscInt  count;
9197068a5610SStefano Zampini } cell_stats_t;
9198068a5610SStefano Zampini 
9199d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9200d71ae5a4SJacob Faibussowitsch {
9201068a5610SStefano Zampini   PetscInt i, N = *len;
9202068a5610SStefano Zampini 
9203068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9204068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9205068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9206068a5610SStefano Zampini 
9207068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9208068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9209068a5610SStefano Zampini     B->sum += A->sum;
9210068a5610SStefano Zampini     B->squaresum += A->squaresum;
9211068a5610SStefano Zampini     B->count += A->count;
9212068a5610SStefano Zampini   }
9213068a5610SStefano Zampini }
9214068a5610SStefano Zampini 
9215068a5610SStefano Zampini /*@
921643fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9217068a5610SStefano Zampini 
921820f4b53cSBarry Smith   Collective
92198261a58bSMatthew G. Knepley 
9220068a5610SStefano Zampini   Input Parameters:
9221a1cb98faSBarry Smith + dm        - The `DMPLEX` object
922220f4b53cSBarry Smith . output    - If true, statistics will be displayed on `stdout`
9223a1cb98faSBarry Smith - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9224a1cb98faSBarry Smith 
9225a1cb98faSBarry Smith   Level: developer
9226068a5610SStefano Zampini 
922795eb5ee5SVaclav Hapla   Notes:
922895eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
922995eb5ee5SVaclav Hapla 
9230a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9231068a5610SStefano Zampini 
92321cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9233068a5610SStefano Zampini @*/
9234d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9235d71ae5a4SJacob Faibussowitsch {
9236068a5610SStefano Zampini   DM           dmCoarse;
923743fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
923843fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
923943fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
924043fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9241412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
924243fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9243068a5610SStefano Zampini 
9244068a5610SStefano Zampini   PetscFunctionBegin;
9245068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9246068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9247068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9248068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9249068a5610SStefano Zampini   stats.count                 = 0;
9250068a5610SStefano Zampini 
92519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
92529566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
92539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
92549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
92559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
92569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9257412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9258068a5610SStefano Zampini     PetscInt  i;
9259068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9260068a5610SStefano Zampini 
92619566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
926263a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
926343fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9264068a5610SStefano Zampini       frobJ += J[i] * J[i];
9265068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9266068a5610SStefano Zampini     }
9267068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9268068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9269068a5610SStefano Zampini 
9270068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9271068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9272068a5610SStefano Zampini     stats.sum += cond;
9273068a5610SStefano Zampini     stats.squaresum += cond2;
9274068a5610SStefano Zampini     stats.count++;
92758261a58bSMatthew G. Knepley     if (output && cond > limit) {
927643fa8764SMatthew G. Knepley       PetscSection coordSection;
927743fa8764SMatthew G. Knepley       Vec          coordsLocal;
927843fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
927943fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
928043fa8764SMatthew G. Knepley 
92819566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
92829566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
92839566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
928463a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
928543fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
928663a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
928743fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
92889566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
92899566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
929043fa8764SMatthew G. Knepley         }
92919566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
929243fa8764SMatthew G. Knepley       }
92939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
929443fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
929543fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
929643fa8764SMatthew G. Knepley 
929743fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
929843fa8764SMatthew G. Knepley           PetscReal len;
929943fa8764SMatthew G. Knepley 
93009566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
930163a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
930243fa8764SMatthew G. Knepley         }
930343fa8764SMatthew G. Knepley       }
93049566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
93059566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
930643fa8764SMatthew G. Knepley     }
9307068a5610SStefano Zampini   }
93089566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9309068a5610SStefano Zampini 
9310068a5610SStefano Zampini   if (size > 1) {
9311068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9312068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9313068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9314068a5610SStefano Zampini     MPI_Op       statReduce;
9315068a5610SStefano Zampini 
93169566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
93179566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
93189566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
93199566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
93209566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
93219566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
9322068a5610SStefano Zampini   } else {
93239566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
9324068a5610SStefano Zampini   }
9325dd400576SPatrick Sanan   if (rank == 0) {
9326068a5610SStefano Zampini     count = globalStats.count;
9327068a5610SStefano Zampini     min   = globalStats.min;
9328068a5610SStefano Zampini     max   = globalStats.max;
9329068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
9330068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
9331068a5610SStefano Zampini   }
9332068a5610SStefano Zampini 
933348a46eb9SPierre Jolivet   if (output) PetscCall(PetscPrintf(comm, "Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double)min, (double)max, (double)mean, (double)stdev));
93349566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
9335068a5610SStefano Zampini 
93369566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
9337068a5610SStefano Zampini   if (dmCoarse) {
9338068a5610SStefano Zampini     PetscBool isplex;
9339068a5610SStefano Zampini 
93409566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
93411baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
9342068a5610SStefano Zampini   }
93433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9344068a5610SStefano Zampini }
9345068a5610SStefano Zampini 
9346f108dbd7SJacob Faibussowitsch /*@
9347f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
9348f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
9349f108dbd7SJacob Faibussowitsch 
935020f4b53cSBarry Smith   Collective
9351f108dbd7SJacob Faibussowitsch 
9352f108dbd7SJacob Faibussowitsch   Input Parameters:
9353a1cb98faSBarry Smith + dm   - The `DMPLEX` object
9354a1cb98faSBarry Smith . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
9355f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
9356f108dbd7SJacob Faibussowitsch 
9357f108dbd7SJacob Faibussowitsch   Output Parameters:
935820f4b53cSBarry Smith + OrthQual      - `Vec` containing orthogonal quality per cell
9359a1cb98faSBarry Smith - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
9360f108dbd7SJacob Faibussowitsch 
9361f108dbd7SJacob Faibussowitsch   Options Database Keys:
9362a1cb98faSBarry Smith + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
9363f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
9364f108dbd7SJacob Faibussowitsch 
9365a1cb98faSBarry Smith   Level: intermediate
9366a1cb98faSBarry Smith 
9367f108dbd7SJacob Faibussowitsch   Notes:
9368f108dbd7SJacob Faibussowitsch   Orthogonal quality is given by the following formula:
9369f108dbd7SJacob Faibussowitsch 
9370a1cb98faSBarry Smith   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
9371f108dbd7SJacob Faibussowitsch 
9372f108dbd7SJacob Faibussowitsch   Where A_i is the i'th face-normal vector, f_i is the vector from the cell centroid to the i'th face centroid, and c_i
9373f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
9374f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
9375f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
9376f108dbd7SJacob Faibussowitsch 
9377f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
9378f108dbd7SJacob Faibussowitsch 
9379a1cb98faSBarry Smith   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
9380f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
9381f108dbd7SJacob Faibussowitsch 
9382f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
9383f108dbd7SJacob Faibussowitsch 
93841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
9385f108dbd7SJacob Faibussowitsch @*/
9386d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
9387d71ae5a4SJacob Faibussowitsch {
93886ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
93896ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
93906ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
9391f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
93926ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
9393f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
9394f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
9395f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
9396f108dbd7SJacob Faibussowitsch   IS                     glob;
9397f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
9398f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
9399f108dbd7SJacob Faibussowitsch 
9400f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
9401f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9402ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
9403f108dbd7SJacob Faibussowitsch   PetscValidPointer(OrthQual, 4);
94046bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
94059566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
94069566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
940763a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
94086ed19f2fSJacob Faibussowitsch   {
94096ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
94106ed19f2fSJacob Faibussowitsch 
94119566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
9412f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
9413f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
9414f108dbd7SJacob Faibussowitsch 
94159566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
941698921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
9417f108dbd7SJacob Faibussowitsch     }
94186ed19f2fSJacob Faibussowitsch   }
9419f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
9420f108dbd7SJacob Faibussowitsch     PetscValidPointer(OrthQualLabel, 5);
94219566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
94229566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
94239371c9d4SSatish Balay   } else {
94249371c9d4SSatish Balay     *OrthQualLabel = NULL;
94259371c9d4SSatish Balay   }
94269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
94279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
94289566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
94299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
94309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
94319566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
94329566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
94339566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
94349566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
94359566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
94369566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
94379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
94389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
94399566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
94409566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
94419566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
94429566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
94439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
94446ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
94456ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9446f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
9447f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
9448898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
9449f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
9450f108dbd7SJacob Faibussowitsch 
94516ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
9452f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
9453f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
94549566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
94559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9456f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
94579566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
94586ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
94596ed19f2fSJacob Faibussowitsch       PetscInt         i;
94606ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
9461f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9462f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
9463f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
9464f108dbd7SJacob Faibussowitsch 
9465f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9466f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
94679566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9468f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
94696ed19f2fSJacob Faibussowitsch       {
94706ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
94716ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
94726ed19f2fSJacob Faibussowitsch 
94739566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
94749566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
94759566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
94766ed19f2fSJacob Faibussowitsch       }
9477f108dbd7SJacob Faibussowitsch 
9478f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9479f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9480f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9481f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9482f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9483addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9484addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9485addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9486f108dbd7SJacob Faibussowitsch       }
9487addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9488addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9489addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9490f108dbd7SJacob Faibussowitsch 
9491f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9492f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9493f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
9494f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
9495f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
9496f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9497f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
9498f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
9499f108dbd7SJacob Faibussowitsch       }
9500ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
9501ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
9502f108dbd7SJacob Faibussowitsch     }
95039566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
95049566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9505f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
95066ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9507f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
95089566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9509f108dbd7SJacob Faibussowitsch     }
9510f108dbd7SJacob Faibussowitsch   }
95119566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
95129566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
95139566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
95149566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
95159566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
95169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9517f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
95189566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9519f108dbd7SJacob Faibussowitsch   }
95209566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
95219566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&vwr));
95229566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
95233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9524f108dbd7SJacob Faibussowitsch }
9525f108dbd7SJacob Faibussowitsch 
9526d5b43468SJose E. Roman /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
95271eb70e55SToby Isaac  * interpolator construction */
9528d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9529d71ae5a4SJacob Faibussowitsch {
95301eb70e55SToby Isaac   PetscSection section, newSection, gsection;
95311eb70e55SToby Isaac   PetscSF      sf;
95321eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
95331eb70e55SToby Isaac 
95341eb70e55SToby Isaac   PetscFunctionBegin;
95351eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95361eb70e55SToby Isaac   PetscValidPointer(odm, 2);
95379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
95389566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
9539712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
95401eb70e55SToby Isaac   if (!ghasConstraints) {
95419566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
95421eb70e55SToby Isaac     *odm = dm;
95433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
95441eb70e55SToby Isaac   }
95459566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
95469566063dSJacob Faibussowitsch   PetscCall(DMCopyFields(dm, *odm));
95479566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
95489566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
95499566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
95509566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
95519566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
95523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
95531eb70e55SToby Isaac }
95541eb70e55SToby Isaac 
9555d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9556d71ae5a4SJacob Faibussowitsch {
95571eb70e55SToby Isaac   DM        dmco, dmfo;
95581eb70e55SToby Isaac   Mat       interpo;
95591eb70e55SToby Isaac   Vec       rscale;
95601eb70e55SToby Isaac   Vec       cglobalo, clocal;
95611eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
95621eb70e55SToby Isaac   PetscBool regular;
95631eb70e55SToby Isaac 
95641eb70e55SToby Isaac   PetscFunctionBegin;
95659566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
95669566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
95679566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
95689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
95699566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
95709566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
95719566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
95729566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
95739566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
95749566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
95759566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
95769566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
95779566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
95789566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
95799566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
95809566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
95819566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
95829566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
95839566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
95849566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
95859566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
95869566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
95879566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
95889566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
95891eb70e55SToby Isaac   *shift = fglobal;
95909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
95919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
95929566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
95939566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
95949566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
95959566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
95969566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
95979566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
95983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
95991eb70e55SToby Isaac }
96001eb70e55SToby Isaac 
9601d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9602d71ae5a4SJacob Faibussowitsch {
96031eb70e55SToby Isaac   PetscObject shifto;
96041eb70e55SToby Isaac   Vec         shift;
96051eb70e55SToby Isaac 
96061eb70e55SToby Isaac   PetscFunctionBegin;
96071eb70e55SToby Isaac   if (!interp) {
96081eb70e55SToby Isaac     Vec rscale;
96091eb70e55SToby Isaac 
96109566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
96119566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
96121eb70e55SToby Isaac   } else {
96139566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
96141eb70e55SToby Isaac   }
96159566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
96161eb70e55SToby Isaac   if (!shifto) {
96179566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
96189566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
96191eb70e55SToby Isaac     shifto = (PetscObject)shift;
96209566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
96211eb70e55SToby Isaac   }
96221eb70e55SToby Isaac   shift = (Vec)shifto;
96239566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
96249566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
96259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
96263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96271eb70e55SToby Isaac }
96281eb70e55SToby Isaac 
9629bceba477SMatthew G. Knepley /* Pointwise interpolation
9630bceba477SMatthew G. Knepley      Just code FEM for now
9631bceba477SMatthew G. Knepley      u^f = I u^c
96324ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
96334ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
96344ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
9635bceba477SMatthew G. Knepley */
9636d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9637d71ae5a4SJacob Faibussowitsch {
9638bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
9639bceba477SMatthew G. Knepley   PetscInt     m, n;
9640a063dac3SMatthew G. Knepley   void        *ctx;
964168132eb9SMatthew G. Knepley   DM           cdm;
9642cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9643bceba477SMatthew G. Knepley 
9644bceba477SMatthew G. Knepley   PetscFunctionBegin;
96459566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
96469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
96479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
96489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
964968132eb9SMatthew G. Knepley 
96509566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
96519566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
96529566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
96539566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
96549566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
965568132eb9SMatthew G. Knepley 
96569566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
96579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
96589566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
96599566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
96609566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
96614db47ee9SStefano Zampini   if (scaling) {
96625d1c2e58SMatthew G. Knepley     /* Use naive scaling */
96639566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
96644db47ee9SStefano Zampini   }
96653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9666a063dac3SMatthew G. Knepley }
9667bceba477SMatthew G. Knepley 
9668d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9669d71ae5a4SJacob Faibussowitsch {
96706dbf9973SLawrence Mitchell   VecScatter ctx;
967190748bafSMatthew G. Knepley 
9672a063dac3SMatthew G. Knepley   PetscFunctionBegin;
96739566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
96749566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
96759566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
96763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9677bceba477SMatthew G. Knepley }
9678bceba477SMatthew G. Knepley 
9679d71ae5a4SJacob Faibussowitsch static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
9680d71ae5a4SJacob Faibussowitsch {
968100635df3SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
968200635df3SMatthew G. Knepley   PetscInt       c;
968300635df3SMatthew G. Knepley   for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
96843e9753d6SMatthew G. Knepley }
96853e9753d6SMatthew G. Knepley 
9686d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9687d71ae5a4SJacob Faibussowitsch {
9688b4937a87SMatthew G. Knepley   DM           dmc;
9689b4937a87SMatthew G. Knepley   PetscDS      ds;
9690b4937a87SMatthew G. Knepley   Vec          ones, locmass;
9691b4937a87SMatthew G. Knepley   IS           cellIS;
9692b4937a87SMatthew G. Knepley   PetscFormKey key;
9693b4937a87SMatthew G. Knepley   PetscInt     depth;
9694b4937a87SMatthew G. Knepley 
9695b4937a87SMatthew G. Knepley   PetscFunctionBegin;
96969566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
96979566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
96989566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
96999566063dSJacob Faibussowitsch   PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
97009566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmc, mass));
97019566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &ones));
97029566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &locmass));
97039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmc, &depth));
97049566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
97059566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
97069566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
9707b4937a87SMatthew G. Knepley   key.label = NULL;
9708b4937a87SMatthew G. Knepley   key.value = 0;
9709b4937a87SMatthew G. Knepley   key.field = 0;
9710b4937a87SMatthew G. Knepley   key.part  = 0;
97119566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
97129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
97139566063dSJacob Faibussowitsch   PetscCall(VecSet(*mass, 0.0));
97149566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
97159566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
97169566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &ones));
97179566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &locmass));
97189566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
97193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9720b4937a87SMatthew G. Knepley }
9721b4937a87SMatthew G. Knepley 
9722d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9723d71ae5a4SJacob Faibussowitsch {
9724bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
9725bd041c0cSMatthew G. Knepley   PetscInt     m, n;
9726bd041c0cSMatthew G. Knepley   void        *ctx;
9727bd041c0cSMatthew G. Knepley   DM           cdm;
9728bd041c0cSMatthew G. Knepley   PetscBool    regular;
9729bd041c0cSMatthew G. Knepley 
9730bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
97313e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
97323e9753d6SMatthew G. Knepley     DM            dmc;
97333e9753d6SMatthew G. Knepley     PetscDS       ds;
9734b4937a87SMatthew G. Knepley     PetscWeakForm wf;
97353e9753d6SMatthew G. Knepley     Vec           u;
97363e9753d6SMatthew G. Knepley     IS            cellIS;
973706ad1575SMatthew G. Knepley     PetscFormKey  key;
97383e9753d6SMatthew G. Knepley     PetscInt      depth;
97393e9753d6SMatthew G. Knepley 
97409566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
97419566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
97429566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
97439566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
97449566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
97459566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
97469566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
97478d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
97489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
97499566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
97509566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
97516528b96dSMatthew G. Knepley     key.label = NULL;
97526528b96dSMatthew G. Knepley     key.value = 0;
97536528b96dSMatthew G. Knepley     key.field = 0;
975406ad1575SMatthew G. Knepley     key.part  = 0;
97559566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
97569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
97578d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
97589566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
97593e9753d6SMatthew G. Knepley   } else {
97609566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
97619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
97629566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
97639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
9764bd041c0cSMatthew G. Knepley 
97659566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
97669566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
97679566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
97689566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
9769bd041c0cSMatthew G. Knepley 
97709566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
97719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
97729566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
97739566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
97743e9753d6SMatthew G. Knepley   }
97759566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
97763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9777bd041c0cSMatthew G. Knepley }
9778bd041c0cSMatthew G. Knepley 
97790aef6b92SMatthew G. Knepley /*@
97800aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
97810aef6b92SMatthew G. Knepley 
97820aef6b92SMatthew G. Knepley   Input Parameter:
9783a1cb98faSBarry Smith . dm - The `DMPLEX` object
97840aef6b92SMatthew G. Knepley 
97850aef6b92SMatthew G. Knepley   Output Parameter:
97860aef6b92SMatthew G. Knepley . regular - The flag
97870aef6b92SMatthew G. Knepley 
97880aef6b92SMatthew G. Knepley   Level: intermediate
97890aef6b92SMatthew G. Knepley 
97901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
97910aef6b92SMatthew G. Knepley @*/
9792d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9793d71ae5a4SJacob Faibussowitsch {
97940aef6b92SMatthew G. Knepley   PetscFunctionBegin;
97950aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9796dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(regular, 2);
97970aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
97983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
97990aef6b92SMatthew G. Knepley }
98000aef6b92SMatthew G. Knepley 
98010aef6b92SMatthew G. Knepley /*@
98020aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
98030aef6b92SMatthew G. Knepley 
98040aef6b92SMatthew G. Knepley   Input Parameters:
9805a1cb98faSBarry Smith + dm - The `DMPLEX` object
98060aef6b92SMatthew G. Knepley - regular - The flag
98070aef6b92SMatthew G. Knepley 
98080aef6b92SMatthew G. Knepley   Level: intermediate
98090aef6b92SMatthew G. Knepley 
98101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
98110aef6b92SMatthew G. Knepley @*/
9812d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9813d71ae5a4SJacob Faibussowitsch {
98140aef6b92SMatthew G. Knepley   PetscFunctionBegin;
98150aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
98160aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
98173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98180aef6b92SMatthew G. Knepley }
98190aef6b92SMatthew G. Knepley 
9820a68b90caSToby Isaac /*@
9821f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9822a1cb98faSBarry Smith   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
9823a68b90caSToby Isaac 
9824a1cb98faSBarry Smith   Not Collective
9825a68b90caSToby Isaac 
9826f899ff85SJose E. Roman   Input Parameter:
9827a1cb98faSBarry Smith . dm - The `DMPLEX` object
9828a68b90caSToby Isaac 
9829a68b90caSToby Isaac   Output Parameters:
983020f4b53cSBarry Smith + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
983120f4b53cSBarry Smith - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection`
9832a68b90caSToby Isaac 
9833a68b90caSToby Isaac   Level: intermediate
9834a68b90caSToby Isaac 
98351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
9836a68b90caSToby Isaac @*/
9837d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9838d71ae5a4SJacob Faibussowitsch {
9839a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
9840a68b90caSToby Isaac 
9841a68b90caSToby Isaac   PetscFunctionBegin;
9842a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
98439566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
9844a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
9845a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
98463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9847a68b90caSToby Isaac }
9848a68b90caSToby Isaac 
9849a68b90caSToby Isaac /*@
9850f7c74593SToby Isaac   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9851f7c74593SToby Isaac   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9852a68b90caSToby Isaac   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9853a68b90caSToby Isaac 
985420f4b53cSBarry Smith   Collective
9855a68b90caSToby Isaac 
9856a68b90caSToby Isaac   Input Parameters:
9857a1cb98faSBarry Smith + dm - The `DMPLEX` object
9858a1cb98faSBarry Smith . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
9859a1cb98faSBarry Smith                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
9860a1cb98faSBarry Smith - anchorIS - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
9861a68b90caSToby Isaac 
9862a68b90caSToby Isaac   Level: intermediate
9863a68b90caSToby Isaac 
9864a1cb98faSBarry Smith   Notes:
9865a1cb98faSBarry Smith   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
9866a1cb98faSBarry Smith   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
9867a1cb98faSBarry Smith 
986820f4b53cSBarry Smith   The reference counts of `anchorSection` and `anchorIS` are incremented.
9869a1cb98faSBarry Smith 
98701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9871a68b90caSToby Isaac @*/
9872d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9873d71ae5a4SJacob Faibussowitsch {
9874a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
9875e228b242SToby Isaac   PetscMPIInt result;
9876a68b90caSToby Isaac 
9877a68b90caSToby Isaac   PetscFunctionBegin;
9878a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9879e228b242SToby Isaac   if (anchorSection) {
9880e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
98819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
98821dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
9883e228b242SToby Isaac   }
9884e228b242SToby Isaac   if (anchorIS) {
9885e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
98869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
98871dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
9888e228b242SToby Isaac   }
9889a68b90caSToby Isaac 
98909566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
98919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
9892a68b90caSToby Isaac   plex->anchorSection = anchorSection;
9893a68b90caSToby Isaac 
98949566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
98959566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
9896a68b90caSToby Isaac   plex->anchorIS = anchorIS;
9897a68b90caSToby Isaac 
9898cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9899a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
9900a68b90caSToby Isaac     const PetscInt *anchors;
9901a68b90caSToby Isaac 
99029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
99039566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
99049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
9905a68b90caSToby Isaac     for (a = 0; a < size; a++) {
9906a68b90caSToby Isaac       PetscInt p;
9907a68b90caSToby Isaac 
9908a68b90caSToby Isaac       p = anchors[a];
9909a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
9910a68b90caSToby Isaac         PetscInt dof;
9911a68b90caSToby Isaac 
99129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
9913a68b90caSToby Isaac         if (dof) {
99149566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
991563a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
9916a68b90caSToby Isaac         }
9917a68b90caSToby Isaac       }
9918a68b90caSToby Isaac     }
99199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
9920a68b90caSToby Isaac   }
9921f7c74593SToby Isaac   /* reset the generic constraints */
99229566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
99233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9924a68b90caSToby Isaac }
9925a68b90caSToby Isaac 
9926d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9927d71ae5a4SJacob Faibussowitsch {
9928f7c74593SToby Isaac   PetscSection anchorSection;
99296995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9930a68b90caSToby Isaac 
9931a68b90caSToby Isaac   PetscFunctionBegin;
9932a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
99339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
99349566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
99359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
99366995de1eSToby Isaac   if (numFields) {
9937719ab38cSToby Isaac     PetscInt f;
99389566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
9939719ab38cSToby Isaac 
9940719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
9941719ab38cSToby Isaac       PetscInt numComp;
9942719ab38cSToby Isaac 
99439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
99449566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
9945719ab38cSToby Isaac     }
99466995de1eSToby Isaac   }
99479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
99489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
99496995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
99506995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
99516995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
99529566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
9953a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
99549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
9955a68b90caSToby Isaac     if (dof) {
99569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
99579566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
9958a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
99599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
99609566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
9961a68b90caSToby Isaac       }
9962a68b90caSToby Isaac     }
9963a68b90caSToby Isaac   }
99649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
99659566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
99663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9967a68b90caSToby Isaac }
9968a68b90caSToby Isaac 
9969d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9970d71ae5a4SJacob Faibussowitsch {
9971f7c74593SToby Isaac   PetscSection    aSec;
9972ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
99730ac89760SToby Isaac   const PetscInt *anchors;
99740ac89760SToby Isaac   PetscInt        numFields, f;
997566ad2231SToby Isaac   IS              aIS;
9976e19f7ee6SMark Adams   MatType         mtype;
9977e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
99780ac89760SToby Isaac 
99790ac89760SToby Isaac   PetscFunctionBegin;
99800ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
99819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
99829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
99839566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
99849566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
99859566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
99869566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
99879566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
99889566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
9989e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9990e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9991e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
99929566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
99939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
99949566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
99956995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
99969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
99979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
99989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
99990ac89760SToby Isaac   i[0] = 0;
100009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
100010ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
10002f19733c5SToby Isaac     PetscInt rDof, rOff, r;
10003f19733c5SToby Isaac 
100049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10005f19733c5SToby Isaac     if (!rDof) continue;
100069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
100070ac89760SToby Isaac     if (numFields) {
100080ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
100090ac89760SToby Isaac         annz = 0;
10010f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
10011f19733c5SToby Isaac           a = anchors[rOff + r];
10012ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
100139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
100140ac89760SToby Isaac           annz += aDof;
100150ac89760SToby Isaac         }
100169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
100179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10018ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
100190ac89760SToby Isaac       }
100202f7452b8SBarry Smith     } else {
100210ac89760SToby Isaac       annz = 0;
100229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
100230ac89760SToby Isaac       for (q = 0; q < dof; q++) {
10024ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
10025ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
100269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
100270ac89760SToby Isaac         annz += aDof;
100280ac89760SToby Isaac       }
100299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
100309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10031ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
100320ac89760SToby Isaac     }
100330ac89760SToby Isaac   }
100340ac89760SToby Isaac   nnz = i[m];
100359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
100360ac89760SToby Isaac   offset = 0;
100370ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
100380ac89760SToby Isaac     if (numFields) {
100390ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
100409566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
100410ac89760SToby Isaac         for (q = 0; q < dof; q++) {
100420ac89760SToby Isaac           PetscInt rDof, rOff, r;
100439566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
100449566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
100450ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
100460ac89760SToby Isaac             PetscInt s;
100470ac89760SToby Isaac 
100480ac89760SToby Isaac             a = anchors[rOff + r];
10049ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
100509566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
100519566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10052ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
100530ac89760SToby Isaac           }
100540ac89760SToby Isaac         }
100550ac89760SToby Isaac       }
100562f7452b8SBarry Smith     } else {
100579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
100580ac89760SToby Isaac       for (q = 0; q < dof; q++) {
100590ac89760SToby Isaac         PetscInt rDof, rOff, r;
100609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
100619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
100620ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
100630ac89760SToby Isaac           PetscInt s;
100640ac89760SToby Isaac 
100650ac89760SToby Isaac           a = anchors[rOff + r];
10066ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
100679566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
100689566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10069ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
100700ac89760SToby Isaac         }
100710ac89760SToby Isaac       }
100720ac89760SToby Isaac     }
100730ac89760SToby Isaac   }
100749566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
100759566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
100769566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
100779566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
100783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100790ac89760SToby Isaac }
100800ac89760SToby Isaac 
10081d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10082d71ae5a4SJacob Faibussowitsch {
10083f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
10084f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
1008566ad2231SToby Isaac   Mat          cMat;
1008666ad2231SToby Isaac 
1008766ad2231SToby Isaac   PetscFunctionBegin;
1008866ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
1009066ad2231SToby Isaac   if (anchorSection) {
1009144a7f3ddSMatthew G. Knepley     PetscInt Nf;
10092e228b242SToby Isaac 
100939566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
100949566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
100959566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
100969566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
100979566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
100989566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
100999566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
101009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
1010166ad2231SToby Isaac   }
101023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1010366ad2231SToby Isaac }
10104a93c429eSMatthew G. Knepley 
10105d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10106d71ae5a4SJacob Faibussowitsch {
10107a93c429eSMatthew G. Knepley   IS           subis;
10108a93c429eSMatthew G. Knepley   PetscSection section, subsection;
10109a93c429eSMatthew G. Knepley 
10110a93c429eSMatthew G. Knepley   PetscFunctionBegin;
101119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1011228b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
1011328b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10114a93c429eSMatthew G. Knepley   /* Create subdomain */
101159566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dm, label, value, subdm));
10116a93c429eSMatthew G. Knepley   /* Create submodel */
101179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
101189566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
101199566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
101209566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
101219566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
10122a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
10123a93c429eSMatthew G. Knepley   if (is) {
10124a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
10125a93c429eSMatthew G. Knepley     IS              spIS;
10126a93c429eSMatthew G. Knepley     const PetscInt *spmap;
10127a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
10128a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10129a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10130a93c429eSMatthew G. Knepley 
101319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
101329566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
101339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
101349566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
101359566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
101369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10137a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10138a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10139a93c429eSMatthew G. Knepley 
101409566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10141a93c429eSMatthew G. Knepley       if (gdof > 0) {
10142a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10143a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10144a93c429eSMatthew G. Knepley 
101459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
101469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10147a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10148a93c429eSMatthew G. Knepley         }
10149a93c429eSMatthew G. Knepley         subSize += pSubSize;
10150a93c429eSMatthew G. Knepley         if (pSubSize) {
10151a93c429eSMatthew G. Knepley           if (bs < 0) {
10152a93c429eSMatthew G. Knepley             bs = pSubSize;
10153a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10154a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10155a93c429eSMatthew G. Knepley             bs = 1;
10156a93c429eSMatthew G. Knepley           }
10157a93c429eSMatthew G. Knepley         }
10158a93c429eSMatthew G. Knepley       }
10159a93c429eSMatthew G. Knepley     }
10160a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
101619371c9d4SSatish Balay     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
101629371c9d4SSatish Balay     bsLocal[1] = bs;
101639566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
101649371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
101659371c9d4SSatish Balay       bs = 1;
101669371c9d4SSatish Balay     } else {
101679371c9d4SSatish Balay       bs = bsMinMax[0];
101689371c9d4SSatish Balay     }
101699566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10170a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10171a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10172a93c429eSMatthew G. Knepley 
101739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10174a93c429eSMatthew G. Knepley       if (gdof > 0) {
10175a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10176a93c429eSMatthew G. Knepley 
101779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10178a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10179a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10180a93c429eSMatthew G. Knepley 
10181a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10182a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
101839566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
101849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10185a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10186a93c429eSMatthew G. Knepley           }
101879566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
101889566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10189ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10190a93c429eSMatthew G. Knepley         }
10191a93c429eSMatthew G. Knepley       }
10192a93c429eSMatthew G. Knepley     }
101939566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
101949566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10195a93c429eSMatthew G. Knepley     if (bs > 1) {
10196a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10197a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10198a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10199a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
102009371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
102019371c9d4SSatish Balay             set = 0;
102029371c9d4SSatish Balay             break;
102039371c9d4SSatish Balay           }
10204a93c429eSMatthew G. Knepley         }
10205a93c429eSMatthew G. Knepley       }
102069566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10207a93c429eSMatthew G. Knepley     }
10208a93c429eSMatthew G. Knepley     /* Attach nullspace */
10209a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
10210a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10211a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
10212a93c429eSMatthew G. Knepley     }
10213a93c429eSMatthew G. Knepley     if (f < Nf) {
10214a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
102159566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
102166823f3c5SBlaise Bourdin 
102179566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
102189566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
10219a93c429eSMatthew G. Knepley     }
10220a93c429eSMatthew G. Knepley   }
102213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10222a93c429eSMatthew G. Knepley }
10223c0f0dcc3SMatthew G. Knepley 
10224c0f0dcc3SMatthew G. Knepley /*@
10225c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10226c0f0dcc3SMatthew G. Knepley 
10227a1cb98faSBarry Smith   Input Parameters:
10228a1cb98faSBarry Smith + dm - The `DM`
10229a1cb98faSBarry Smith - dummy - unused argument
10230a1cb98faSBarry Smith 
10231a1cb98faSBarry Smith   Options Database Key:
10232a1cb98faSBarry Smith . -dm_plex_monitor_throughput - Activate the monitor
10233c0f0dcc3SMatthew G. Knepley 
10234c0f0dcc3SMatthew G. Knepley   Level: developer
10235c0f0dcc3SMatthew G. Knepley 
102361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10237c0f0dcc3SMatthew G. Knepley @*/
10238d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
10239d71ae5a4SJacob Faibussowitsch {
10240e5ed2c37SJose E. Roman #if defined(PETSC_USE_LOG)
10241c0f0dcc3SMatthew G. Knepley   PetscStageLog      stageLog;
10242c0f0dcc3SMatthew G. Knepley   PetscLogEvent      event;
10243c0f0dcc3SMatthew G. Knepley   PetscLogStage      stage;
10244c0f0dcc3SMatthew G. Knepley   PetscEventPerfInfo eventInfo;
10245c0f0dcc3SMatthew G. Knepley   PetscReal          cellRate, flopRate;
10246c0f0dcc3SMatthew G. Knepley   PetscInt           cStart, cEnd, Nf, N;
10247c0f0dcc3SMatthew G. Knepley   const char        *name;
10248e5ed2c37SJose E. Roman #endif
10249c0f0dcc3SMatthew G. Knepley 
10250c0f0dcc3SMatthew G. Knepley   PetscFunctionBegin;
10251c0f0dcc3SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10252c0f0dcc3SMatthew G. Knepley #if defined(PETSC_USE_LOG)
102539566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
102549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
102559566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
102569566063dSJacob Faibussowitsch   PetscCall(PetscLogGetStageLog(&stageLog));
102579566063dSJacob Faibussowitsch   PetscCall(PetscStageLogGetCurrent(stageLog, &stage));
102589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
102599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo));
10260c0f0dcc3SMatthew G. Knepley   N        = (cEnd - cStart) * Nf * eventInfo.count;
10261c0f0dcc3SMatthew G. Knepley   flopRate = eventInfo.flops / eventInfo.time;
10262c0f0dcc3SMatthew G. Knepley   cellRate = N / eventInfo.time;
1026363a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " integrals %d reps\n  Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double)cellRate, (double)(flopRate / 1.e6)));
10264c0f0dcc3SMatthew G. Knepley #else
10265c0f0dcc3SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
10266c0f0dcc3SMatthew G. Knepley #endif
102673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10268c0f0dcc3SMatthew G. Knepley }
10269