xref: /petsc/src/dm/impls/plex/plex.c (revision 9f4ada1598380228c679a94df7f1b051b1b79bf6)
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;
14252a1336SBarry Smith PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart;
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:
229318fe57SMatthew G. Knepley . 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   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
289318fe57SMatthew G. Knepley   If the mesh has no cells, this returns PETSC_FALSE.
299318fe57SMatthew G. Knepley 
309318fe57SMatthew G. Knepley   Level: intermediate
319318fe57SMatthew G. Knepley 
32db781477SPatrick Sanan .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
339318fe57SMatthew G. Knepley @*/
34d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
35d71ae5a4SJacob Faibussowitsch {
369318fe57SMatthew G. Knepley   DMPolytopeType ct;
379318fe57SMatthew G. Knepley   PetscInt       cStart, cEnd;
389318fe57SMatthew G. Knepley 
399318fe57SMatthew G. Knepley   PetscFunctionBegin;
409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
419371c9d4SSatish Balay   if (cEnd <= cStart) {
429371c9d4SSatish Balay     *simplex = PETSC_FALSE;
439371c9d4SSatish Balay     PetscFunctionReturn(0);
449371c9d4SSatish Balay   }
459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
469318fe57SMatthew G. Knepley   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
479318fe57SMatthew G. Knepley   PetscFunctionReturn(0);
489318fe57SMatthew G. Knepley }
499318fe57SMatthew G. Knepley 
509318fe57SMatthew G. Knepley /*@
51412e9a14SMatthew G. Knepley   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
52e5337592SStefano Zampini 
53d8d19677SJose E. Roman   Input Parameters:
54412e9a14SMatthew G. Knepley + dm     - The DMPlex object
55412e9a14SMatthew G. Knepley - height - The cell height in the Plex, 0 is the default
56e5337592SStefano Zampini 
57e5337592SStefano Zampini   Output Parameters:
58412e9a14SMatthew G. Knepley + cStart - The first "normal" cell
59412e9a14SMatthew G. Knepley - cEnd   - The upper bound on "normal"" cells
60e5337592SStefano Zampini 
61412e9a14SMatthew G. Knepley   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
62e5337592SStefano Zampini 
63412e9a14SMatthew G. Knepley   Level: developer
64e5337592SStefano Zampini 
65db781477SPatrick Sanan .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()`
66e5337592SStefano Zampini @*/
67d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
68d71ae5a4SJacob Faibussowitsch {
69412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
70412e9a14SMatthew G. Knepley   PetscInt       cS, cE, c;
71e5337592SStefano Zampini 
72e5337592SStefano Zampini   PetscFunctionBegin;
739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE));
74412e9a14SMatthew G. Knepley   for (c = cS; c < cE; ++c) {
75412e9a14SMatthew G. Knepley     DMPolytopeType cct;
76412e9a14SMatthew G. Knepley 
779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &cct));
78412e9a14SMatthew G. Knepley     if ((PetscInt)cct < 0) break;
79412e9a14SMatthew G. Knepley     switch (cct) {
80ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_POINT:
81ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
82ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
83ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
84ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
85d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_HEXAHEDRON:
86d71ae5a4SJacob Faibussowitsch       ct = cct;
87d71ae5a4SJacob Faibussowitsch       break;
88d71ae5a4SJacob Faibussowitsch     default:
89d71ae5a4SJacob Faibussowitsch       break;
90e5337592SStefano Zampini     }
91412e9a14SMatthew G. Knepley     if (ct != DM_POLYTOPE_UNKNOWN) break;
92e5337592SStefano Zampini   }
93412e9a14SMatthew G. Knepley   if (ct != DM_POLYTOPE_UNKNOWN) {
94412e9a14SMatthew G. Knepley     DMLabel ctLabel;
95412e9a14SMatthew G. Knepley 
969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
979566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE));
98695799ffSMatthew G. Knepley     // Reset label for fast lookup
99695799ffSMatthew G. Knepley     PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
100e5337592SStefano Zampini   }
101412e9a14SMatthew G. Knepley   if (cStart) *cStart = cS;
102412e9a14SMatthew G. Knepley   if (cEnd) *cEnd = cE;
103e5337592SStefano Zampini   PetscFunctionReturn(0);
104e5337592SStefano Zampini }
105e5337592SStefano Zampini 
106d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
107d71ae5a4SJacob Faibussowitsch {
108412e9a14SMatthew G. Knepley   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
109a99a26bcSAdrian Croucher   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
1107e42fee7SMatthew G. Knepley 
1117e42fee7SMatthew G. Knepley   PetscFunctionBegin;
112e630c359SToby Isaac   *ft = PETSC_VTK_INVALID;
1139566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1169566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1177e42fee7SMatthew G. Knepley   if (field >= 0) {
1189566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
1199566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
1207e42fee7SMatthew G. Knepley   } else {
1219566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
1229566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
1237e42fee7SMatthew G. Knepley   }
1249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
125a99a26bcSAdrian Croucher   if (globalvcdof[0]) {
1267e42fee7SMatthew G. Knepley     *sStart = vStart;
1277e42fee7SMatthew G. Knepley     *sEnd   = vEnd;
128f094498dSMatthew G. Knepley     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
1297e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_POINT_FIELD;
130a99a26bcSAdrian Croucher   } else if (globalvcdof[1]) {
1317e42fee7SMatthew G. Knepley     *sStart = cStart;
1327e42fee7SMatthew G. Knepley     *sEnd   = cEnd;
133f094498dSMatthew G. Knepley     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
1347e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_CELL_FIELD;
135e630c359SToby Isaac   } else {
136e630c359SToby Isaac     if (field >= 0) {
137e630c359SToby Isaac       const char *fieldname;
138e630c359SToby Isaac 
1399566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
14063a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
141e630c359SToby Isaac     } else {
14263a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
143e630c359SToby Isaac     }
144e630c359SToby Isaac   }
1457e42fee7SMatthew G. Knepley   PetscFunctionReturn(0);
1467e42fee7SMatthew G. Knepley }
1477e42fee7SMatthew G. Knepley 
1486913077dSMatthew G. Knepley /*@
1496913077dSMatthew G. Knepley   DMPlexVecView1D - Plot many 1D solutions on the same line graph
1506913077dSMatthew G. Knepley 
1516913077dSMatthew G. Knepley   Collective on dm
1526913077dSMatthew G. Knepley 
1536913077dSMatthew G. Knepley   Input Parameters:
1546913077dSMatthew G. Knepley + dm - The DMPlex
1556913077dSMatthew G. Knepley . n  - The number of vectors
1566913077dSMatthew G. Knepley . u  - The array of local vectors
1576913077dSMatthew G. Knepley - viewer - The Draw viewer
1586913077dSMatthew G. Knepley 
1596913077dSMatthew G. Knepley   Level: advanced
1606913077dSMatthew G. Knepley 
161db781477SPatrick Sanan .seealso: `VecViewFromOptions()`, `VecView()`
1626913077dSMatthew G. Knepley @*/
163d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
164d71ae5a4SJacob Faibussowitsch {
1656913077dSMatthew G. Knepley   PetscDS            ds;
1666913077dSMatthew G. Knepley   PetscDraw          draw = NULL;
1676913077dSMatthew G. Knepley   PetscDrawLG        lg;
1686913077dSMatthew G. Knepley   Vec                coordinates;
1696913077dSMatthew G. Knepley   const PetscScalar *coords, **sol;
1706913077dSMatthew G. Knepley   PetscReal         *vals;
1716913077dSMatthew G. Knepley   PetscInt          *Nc;
1726913077dSMatthew G. Knepley   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
1736913077dSMatthew G. Knepley   char             **names;
1746913077dSMatthew G. Knepley 
1756913077dSMatthew G. Knepley   PetscFunctionBegin;
1769566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
1779566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
1789566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
1799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponents(ds, &Nc));
1806913077dSMatthew G. Knepley 
1819566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1826913077dSMatthew G. Knepley   if (!draw) PetscFunctionReturn(0);
1839566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
1846913077dSMatthew G. Knepley 
1859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
1866913077dSMatthew G. Knepley   for (i = 0, l = 0; i < n; ++i) {
1876913077dSMatthew G. Knepley     const char *vname;
1886913077dSMatthew G. Knepley 
1899566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
1906913077dSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
1916913077dSMatthew G. Knepley       PetscObject disc;
1926913077dSMatthew G. Knepley       const char *fname;
1936913077dSMatthew G. Knepley       char        tmpname[PETSC_MAX_PATH_LEN];
1946913077dSMatthew G. Knepley 
1959566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
1966913077dSMatthew G. Knepley       /* TODO Create names for components */
1976913077dSMatthew G. Knepley       for (c = 0; c < Nc[f]; ++c, ++l) {
1989566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(disc, &fname));
1999566063dSJacob Faibussowitsch         PetscCall(PetscStrcpy(tmpname, vname));
2009566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN));
2019566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN));
2029566063dSJacob Faibussowitsch         PetscCall(PetscStrallocpy(tmpname, &names[l]));
2036913077dSMatthew G. Knepley       }
2046913077dSMatthew G. Knepley     }
2056913077dSMatthew G. Knepley   }
2069566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
2076913077dSMatthew G. Knepley   /* Just add P_1 support for now */
2089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2109566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
2119566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
2126913077dSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
2136913077dSMatthew G. Knepley     PetscScalar *x, *svals;
2146913077dSMatthew G. Knepley 
2159566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
2166913077dSMatthew G. Knepley     for (i = 0; i < n; ++i) {
2179566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
2186913077dSMatthew G. Knepley       for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
2196913077dSMatthew G. Knepley     }
2209566063dSJacob Faibussowitsch     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
2216913077dSMatthew G. Knepley   }
2229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
2239566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
2249566063dSJacob Faibussowitsch   for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
2259566063dSJacob Faibussowitsch   PetscCall(PetscFree3(sol, names, vals));
2266913077dSMatthew G. Knepley 
2279566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDraw(lg));
2289566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDestroy(&lg));
2296913077dSMatthew G. Knepley   PetscFunctionReturn(0);
2306913077dSMatthew G. Knepley }
2316913077dSMatthew G. Knepley 
232d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
233d71ae5a4SJacob Faibussowitsch {
2346913077dSMatthew G. Knepley   DM dm;
2356913077dSMatthew G. Knepley 
2366913077dSMatthew G. Knepley   PetscFunctionBegin;
2379566063dSJacob Faibussowitsch   PetscCall(VecGetDM(u, &dm));
2389566063dSJacob Faibussowitsch   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
2396913077dSMatthew G. Knepley   PetscFunctionReturn(0);
2406913077dSMatthew G. Knepley }
2416913077dSMatthew G. Knepley 
242d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
243d71ae5a4SJacob Faibussowitsch {
244e412dcbdSMatthew G. Knepley   DM                 dm;
245d1df6f1dSMatthew G. Knepley   PetscSection       s;
246e412dcbdSMatthew G. Knepley   PetscDraw          draw, popup;
247e412dcbdSMatthew G. Knepley   DM                 cdm;
248e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
249e412dcbdSMatthew G. Knepley   Vec                coordinates;
250e412dcbdSMatthew G. Knepley   const PetscScalar *coords, *array;
251e412dcbdSMatthew G. Knepley   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
252339e3443SMatthew G. Knepley   PetscReal          vbound[2], time;
2536913077dSMatthew G. Knepley   PetscBool          flg;
254d1df6f1dSMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
255e412dcbdSMatthew G. Knepley   const char        *name;
256339e3443SMatthew G. Knepley   char               title[PETSC_MAX_PATH_LEN];
257e412dcbdSMatthew G. Knepley 
258e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
2599566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2609566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
2619566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
2629566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
2639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
2649566063dSJacob Faibussowitsch   PetscCall(DMGetCoarsenLevel(dm, &level));
2659566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
2669566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
2679566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
270e412dcbdSMatthew G. Knepley 
2719566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
2729566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
273e412dcbdSMatthew G. Knepley 
2749566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
2759566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
276e412dcbdSMatthew G. Knepley   for (c = 0; c < N; c += dim) {
2779371c9d4SSatish Balay     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));
2789371c9d4SSatish Balay     bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
2799371c9d4SSatish Balay     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1]));
2809371c9d4SSatish Balay     bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1]));
281e412dcbdSMatthew G. Knepley   }
2829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
2839566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
284e412dcbdSMatthew G. Knepley 
285d1df6f1dSMatthew G. Knepley   /* Could implement something like DMDASelectFields() */
286d1df6f1dSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
287d1df6f1dSMatthew G. Knepley     DM          fdm = dm;
288d1df6f1dSMatthew G. Knepley     Vec         fv  = v;
289d1df6f1dSMatthew G. Knepley     IS          fis;
290d1df6f1dSMatthew G. Knepley     char        prefix[PETSC_MAX_PATH_LEN];
291d1df6f1dSMatthew G. Knepley     const char *fname;
292d1df6f1dSMatthew G. Knepley 
2939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(s, f, &fname));
295d1df6f1dSMatthew G. Knepley 
2969566063dSJacob Faibussowitsch     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
297ad540459SPierre Jolivet     else prefix[0] = '\0';
298d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
2999566063dSJacob Faibussowitsch       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
3009566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(v, fis, &fv));
3019566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
3029566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
303d1df6f1dSMatthew G. Knepley     }
304d1df6f1dSMatthew G. Knepley     for (comp = 0; comp < Nc; ++comp, ++w) {
305d1df6f1dSMatthew G. Knepley       PetscInt nmax = 2;
306d1df6f1dSMatthew G. Knepley 
3079566063dSJacob Faibussowitsch       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
30863a3b9bcSJacob Faibussowitsch       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
30963a3b9bcSJacob Faibussowitsch       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
3109566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetTitle(draw, title));
311d1df6f1dSMatthew G. Knepley 
312d1df6f1dSMatthew G. Knepley       /* TODO Get max and min only for this component */
3139566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
314339e3443SMatthew G. Knepley       if (!flg) {
3159566063dSJacob Faibussowitsch         PetscCall(VecMin(fv, NULL, &vbound[0]));
3169566063dSJacob Faibussowitsch         PetscCall(VecMax(fv, NULL, &vbound[1]));
317d1df6f1dSMatthew G. Knepley         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
318339e3443SMatthew G. Knepley       }
3199566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetPopup(draw, &popup));
3209566063dSJacob Faibussowitsch       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
3219566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]));
322e412dcbdSMatthew G. Knepley 
3239566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(fv, &array));
324e412dcbdSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
32599a2f7bcSMatthew G. Knepley         PetscScalar *coords = NULL, *a   = NULL;
326e56f9228SJed Brown         PetscInt     numCoords, color[4] = {-1, -1, -1, -1};
327e412dcbdSMatthew G. Knepley 
3289566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
329339e3443SMatthew G. Knepley         if (a) {
330d1df6f1dSMatthew G. Knepley           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
331339e3443SMatthew G. Knepley           color[1] = color[2] = color[3] = color[0];
332339e3443SMatthew G. Knepley         } else {
333339e3443SMatthew G. Knepley           PetscScalar *vals = NULL;
334339e3443SMatthew G. Knepley           PetscInt     numVals, va;
335339e3443SMatthew G. Knepley 
3369566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
33763a3b9bcSJacob 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);
338d1df6f1dSMatthew G. Knepley           switch (numVals / Nc) {
339d1df6f1dSMatthew G. Knepley           case 3: /* P1 Triangle */
340d1df6f1dSMatthew G. Knepley           case 4: /* P1 Quadrangle */
341d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
342339e3443SMatthew G. Knepley             break;
343d1df6f1dSMatthew G. Knepley           case 6: /* P2 Triangle */
344d1df6f1dSMatthew G. Knepley           case 8: /* P2 Quadrangle */
345d1df6f1dSMatthew 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]);
346d1df6f1dSMatthew G. Knepley             break;
347d71ae5a4SJacob Faibussowitsch           default:
348d71ae5a4SJacob Faibussowitsch             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
349339e3443SMatthew G. Knepley           }
3509566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
351339e3443SMatthew G. Knepley         }
3529566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
353e412dcbdSMatthew G. Knepley         switch (numCoords) {
354e412dcbdSMatthew G. Knepley         case 6:
3559edc3542SMatthew Knepley         case 12: /* Localized triangle */
3569566063dSJacob 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]));
357e412dcbdSMatthew G. Knepley           break;
358e412dcbdSMatthew G. Knepley         case 8:
3599edc3542SMatthew Knepley         case 16: /* Localized quadrilateral */
3609566063dSJacob 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]));
3619566063dSJacob 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]));
362e412dcbdSMatthew G. Knepley           break;
363d71ae5a4SJacob Faibussowitsch         default:
364d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
365e412dcbdSMatthew G. Knepley         }
3669566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
367e412dcbdSMatthew G. Knepley       }
3689566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(fv, &array));
3699566063dSJacob Faibussowitsch       PetscCall(PetscDrawFlush(draw));
3709566063dSJacob Faibussowitsch       PetscCall(PetscDrawPause(draw));
3719566063dSJacob Faibussowitsch       PetscCall(PetscDrawSave(draw));
372d1df6f1dSMatthew G. Knepley     }
373d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
3749566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(v, fis, &fv));
3759566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&fis));
3769566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&fdm));
377d1df6f1dSMatthew G. Knepley     }
378d1df6f1dSMatthew G. Knepley   }
379e412dcbdSMatthew G. Knepley   PetscFunctionReturn(0);
380e412dcbdSMatthew G. Knepley }
381e412dcbdSMatthew G. Knepley 
382d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
383d71ae5a4SJacob Faibussowitsch {
3846913077dSMatthew G. Knepley   DM        dm;
3856913077dSMatthew G. Knepley   PetscDraw draw;
3866913077dSMatthew G. Knepley   PetscInt  dim;
3876913077dSMatthew G. Knepley   PetscBool isnull;
3886913077dSMatthew G. Knepley 
3896913077dSMatthew G. Knepley   PetscFunctionBegin;
3909566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3919566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
3926913077dSMatthew G. Knepley   if (isnull) PetscFunctionReturn(0);
3936913077dSMatthew G. Knepley 
3949566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
3959566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
3966913077dSMatthew G. Knepley   switch (dim) {
397d71ae5a4SJacob Faibussowitsch   case 1:
398d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
399d71ae5a4SJacob Faibussowitsch     break;
400d71ae5a4SJacob Faibussowitsch   case 2:
401d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
402d71ae5a4SJacob Faibussowitsch     break;
403d71ae5a4SJacob Faibussowitsch   default:
404d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
4056913077dSMatthew G. Knepley   }
4066913077dSMatthew G. Knepley   PetscFunctionReturn(0);
4076913077dSMatthew G. Knepley }
4086913077dSMatthew G. Knepley 
409d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
410d71ae5a4SJacob Faibussowitsch {
411684b87d9SLisandro Dalcin   DM                      dm;
412684b87d9SLisandro Dalcin   Vec                     locv;
413684b87d9SLisandro Dalcin   const char             *name;
414684b87d9SLisandro Dalcin   PetscSection            section;
415684b87d9SLisandro Dalcin   PetscInt                pStart, pEnd;
416e630c359SToby Isaac   PetscInt                numFields;
417684b87d9SLisandro Dalcin   PetscViewerVTKFieldType ft;
418684b87d9SLisandro Dalcin 
419684b87d9SLisandro Dalcin   PetscFunctionBegin;
4209566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
4219566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
4229566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
4239566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)locv, name));
4249566063dSJacob Faibussowitsch   PetscCall(VecCopy(v, locv));
4259566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
4269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
427e630c359SToby Isaac   if (!numFields) {
4289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
4299566063dSJacob Faibussowitsch     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
430e630c359SToby Isaac   } else {
431e630c359SToby Isaac     PetscInt f;
432e630c359SToby Isaac 
433e630c359SToby Isaac     for (f = 0; f < numFields; f++) {
4349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
435e630c359SToby Isaac       if (ft == PETSC_VTK_INVALID) continue;
4369566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)locv));
4379566063dSJacob Faibussowitsch       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
438e630c359SToby Isaac     }
4399566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locv));
440e630c359SToby Isaac   }
441684b87d9SLisandro Dalcin   PetscFunctionReturn(0);
442684b87d9SLisandro Dalcin }
443684b87d9SLisandro Dalcin 
444d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
445d71ae5a4SJacob Faibussowitsch {
446552f7358SJed Brown   DM        dm;
4475f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;
448552f7358SJed Brown 
449552f7358SJed Brown   PetscFunctionBegin;
4509566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
45128b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
4529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
4539566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
4559566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
4565f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
4575f34f2dcSJed Brown   if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
458684b87d9SLisandro Dalcin     PetscInt    i, numFields;
459684b87d9SLisandro Dalcin     PetscObject fe;
460ef31f671SMatthew G. Knepley     PetscBool   fem  = PETSC_FALSE;
461684b87d9SLisandro Dalcin     Vec         locv = v;
462684b87d9SLisandro Dalcin     const char *name;
463684b87d9SLisandro Dalcin     PetscInt    step;
464684b87d9SLisandro Dalcin     PetscReal   time;
465ef31f671SMatthew G. Knepley 
4669566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &numFields));
467684b87d9SLisandro Dalcin     for (i = 0; i < numFields; i++) {
4689566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, i, NULL, &fe));
4699371c9d4SSatish Balay       if (fe->classid == PETSCFE_CLASSID) {
4709371c9d4SSatish Balay         fem = PETSC_TRUE;
4719371c9d4SSatish Balay         break;
4729371c9d4SSatish Balay       }
473ef31f671SMatthew G. Knepley     }
474684b87d9SLisandro Dalcin     if (fem) {
475798534f6SMatthew G. Knepley       PetscObject isZero;
476798534f6SMatthew G. Knepley 
4779566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &locv));
4789566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)v, &name));
4799566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)locv, name));
4809566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
4819566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
4829566063dSJacob Faibussowitsch       PetscCall(VecCopy(v, locv));
4839566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
4849566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
485ef31f671SMatthew G. Knepley     }
486552f7358SJed Brown     if (isvtk) {
4879566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
488b136c2c9SMatthew G. Knepley     } else if (ishdf5) {
489b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
4909566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
491b136c2c9SMatthew G. Knepley #else
492b136c2c9SMatthew G. Knepley       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
493b136c2c9SMatthew G. Knepley #endif
494f13a32a3SMatthew G. Knepley     } else if (isdraw) {
4959566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
496684b87d9SLisandro Dalcin     } else if (isglvis) {
4979566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
4989566063dSJacob Faibussowitsch       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
4999566063dSJacob Faibussowitsch       PetscCall(VecView_GLVis(locv, viewer));
5005f34f2dcSJed Brown     } else if (iscgns) {
5015f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
5025f34f2dcSJed Brown       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
5035f34f2dcSJed Brown #else
5045f34f2dcSJed Brown       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
5055f34f2dcSJed Brown #endif
506684b87d9SLisandro Dalcin     }
507798534f6SMatthew G. Knepley     if (fem) {
5089566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
5099566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &locv));
510798534f6SMatthew G. Knepley     }
511552f7358SJed Brown   } else {
512684b87d9SLisandro Dalcin     PetscBool isseq;
513684b87d9SLisandro Dalcin 
5149566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
5159566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
5169566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
517552f7358SJed Brown   }
518552f7358SJed Brown   PetscFunctionReturn(0);
519552f7358SJed Brown }
520552f7358SJed Brown 
521d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
522d71ae5a4SJacob Faibussowitsch {
523552f7358SJed Brown   DM        dm;
5245f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;
525552f7358SJed Brown 
526552f7358SJed Brown   PetscFunctionBegin;
5279566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
52828b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
5309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
5335f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
5349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
5355f34f2dcSJed Brown   if (isvtk || isdraw || isglvis || iscgns) {
536552f7358SJed Brown     Vec         locv;
537798534f6SMatthew G. Knepley     PetscObject isZero;
538552f7358SJed Brown     const char *name;
539552f7358SJed Brown 
5409566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &locv));
5419566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
5429566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)locv, name));
5439566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
5449566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
5459566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
5469566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
5479566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_Local(locv, viewer));
5489566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
5499566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &locv));
550b136c2c9SMatthew G. Knepley   } else if (ishdf5) {
551b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
5529566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
553b136c2c9SMatthew G. Knepley #else
554b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
555b136c2c9SMatthew G. Knepley #endif
5566823f3c5SBlaise Bourdin   } else if (isexodusii) {
5576823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
5589566063dSJacob Faibussowitsch     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
5596823f3c5SBlaise Bourdin #else
5606823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
5616823f3c5SBlaise Bourdin #endif
562552f7358SJed Brown   } else {
563684b87d9SLisandro Dalcin     PetscBool isseq;
564684b87d9SLisandro Dalcin 
5659566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
5669566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
5679566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
568552f7358SJed Brown   }
569552f7358SJed Brown   PetscFunctionReturn(0);
570552f7358SJed Brown }
571552f7358SJed Brown 
572d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
573d71ae5a4SJacob Faibussowitsch {
574d930f514SMatthew G. Knepley   DM                dm;
575d930f514SMatthew G. Knepley   MPI_Comm          comm;
576d930f514SMatthew G. Knepley   PetscViewerFormat format;
577d930f514SMatthew G. Knepley   Vec               v;
578d930f514SMatthew G. Knepley   PetscBool         isvtk, ishdf5;
579d930f514SMatthew G. Knepley 
580d930f514SMatthew G. Knepley   PetscFunctionBegin;
5819566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
5829566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
58328b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5849566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
5859566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5869566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
587d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
588a8ad634aSStefano Zampini     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
589a8ad634aSStefano Zampini     /* this need a better fix */
590a8ad634aSStefano Zampini     if (dm->useNatural) {
591a8ad634aSStefano Zampini       if (dm->sfNatural) {
592d930f514SMatthew G. Knepley         const char *vecname;
593d930f514SMatthew G. Knepley         PetscInt    n, nroots;
594d930f514SMatthew G. Knepley 
5959566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(originalv, &n));
5969566063dSJacob Faibussowitsch         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
597d930f514SMatthew G. Knepley         if (n == nroots) {
5989566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalVector(dm, &v));
5999566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
6009566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
6019566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
6029566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
603d930f514SMatthew G. Knepley         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
604d930f514SMatthew G. Knepley       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
605a8ad634aSStefano Zampini     } else v = originalv;
606a8ad634aSStefano Zampini   } else v = originalv;
607a8ad634aSStefano Zampini 
608d930f514SMatthew G. Knepley   if (ishdf5) {
609d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6109566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
611d930f514SMatthew G. Knepley #else
612d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
613d930f514SMatthew G. Knepley #endif
614d930f514SMatthew G. Knepley   } else if (isvtk) {
615d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
616d930f514SMatthew G. Knepley   } else {
617d930f514SMatthew G. Knepley     PetscBool isseq;
618d930f514SMatthew G. Knepley 
6199566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
6209566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
6219566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
622d930f514SMatthew G. Knepley   }
6239566063dSJacob Faibussowitsch   if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v));
624d930f514SMatthew G. Knepley   PetscFunctionReturn(0);
625d930f514SMatthew G. Knepley }
626d930f514SMatthew G. Knepley 
627d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
628d71ae5a4SJacob Faibussowitsch {
6292c40f234SMatthew G. Knepley   DM        dm;
6302c40f234SMatthew G. Knepley   PetscBool ishdf5;
6312c40f234SMatthew G. Knepley 
6322c40f234SMatthew G. Knepley   PetscFunctionBegin;
6339566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
63428b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6362c40f234SMatthew G. Knepley   if (ishdf5) {
6372c40f234SMatthew G. Knepley     DM          dmBC;
6382c40f234SMatthew G. Knepley     Vec         gv;
6392c40f234SMatthew G. Knepley     const char *name;
6402c40f234SMatthew G. Knepley 
6419566063dSJacob Faibussowitsch     PetscCall(DMGetOutputDM(dm, &dmBC));
6429566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmBC, &gv));
6439566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
6449566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)gv, name));
6459566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(gv, viewer));
6469566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
6479566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
6489566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
6491baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
6502c40f234SMatthew G. Knepley   PetscFunctionReturn(0);
6512c40f234SMatthew G. Knepley }
6522c40f234SMatthew G. Knepley 
653d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
654d71ae5a4SJacob Faibussowitsch {
6552c40f234SMatthew G. Knepley   DM        dm;
6566823f3c5SBlaise Bourdin   PetscBool ishdf5, isexodusii;
6572c40f234SMatthew G. Knepley 
6582c40f234SMatthew G. Knepley   PetscFunctionBegin;
6599566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
66028b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
6632c40f234SMatthew G. Knepley   if (ishdf5) {
664878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6659566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
666b136c2c9SMatthew G. Knepley #else
667b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
668878b459fSMatthew G. Knepley #endif
6696823f3c5SBlaise Bourdin   } else if (isexodusii) {
6706823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
6719566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
6726823f3c5SBlaise Bourdin #else
6736823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
6746823f3c5SBlaise Bourdin #endif
6751baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
676552f7358SJed Brown   PetscFunctionReturn(0);
677552f7358SJed Brown }
678552f7358SJed Brown 
679d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
680d71ae5a4SJacob Faibussowitsch {
681d930f514SMatthew G. Knepley   DM                dm;
682d930f514SMatthew G. Knepley   PetscViewerFormat format;
683d930f514SMatthew G. Knepley   PetscBool         ishdf5;
684d930f514SMatthew G. Knepley 
685d930f514SMatthew G. Knepley   PetscFunctionBegin;
6869566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
68728b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6889566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
6899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
690d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
691a8ad634aSStefano Zampini     if (dm->useNatural) {
692d930f514SMatthew G. Knepley       if (dm->sfNatural) {
693d930f514SMatthew G. Knepley         if (ishdf5) {
694d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
695d930f514SMatthew G. Knepley           Vec         v;
696d930f514SMatthew G. Knepley           const char *vecname;
697d930f514SMatthew G. Knepley 
6989566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalVector(dm, &v));
6999566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
7009566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
7019566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
7029566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
7039566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
7049566063dSJacob Faibussowitsch           PetscCall(DMRestoreGlobalVector(dm, &v));
705d930f514SMatthew G. Knepley #else
706d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
707d930f514SMatthew G. Knepley #endif
708d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
709d930f514SMatthew G. Knepley       }
7101baa6e33SBarry Smith     } else PetscCall(VecLoad_Default(originalv, viewer));
711d930f514SMatthew G. Knepley   }
712d930f514SMatthew G. Knepley   PetscFunctionReturn(0);
713d930f514SMatthew G. Knepley }
714d930f514SMatthew G. Knepley 
715d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
716d71ae5a4SJacob Faibussowitsch {
717731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
718731e8ddeSMatthew G. Knepley   Vec                coordinates;
719ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
720731e8ddeSMatthew G. Knepley   const char        *name[4];
721731e8ddeSMatthew G. Knepley   const PetscScalar *a;
722731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
723731e8ddeSMatthew G. Knepley 
724731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
7259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
7269566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
7279566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
7299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
7309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
7329566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
733731e8ddeSMatthew G. Knepley   name[0]       = "vertex";
734731e8ddeSMatthew G. Knepley   name[1]       = "edge";
735731e8ddeSMatthew G. Knepley   name[dim - 1] = "face";
736731e8ddeSMatthew G. Knepley   name[dim]     = "cell";
737731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
738731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
739ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
740731e8ddeSMatthew G. Knepley 
7419566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
74263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
7439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7449566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
745731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
746731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
747731e8ddeSMatthew G. Knepley 
748731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
7499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
750731e8ddeSMatthew G. Knepley       if (!dof) continue;
7519566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
7529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
75363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
754731e8ddeSMatthew G. Knepley       for (p = 0; p < dof / dim; ++p) {
7559566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
756731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
7579566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
7589566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
759731e8ddeSMatthew G. Knepley         }
7609566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
761731e8ddeSMatthew G. Knepley       }
7629566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
763731e8ddeSMatthew G. Knepley     }
7649566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7659566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
766731e8ddeSMatthew G. Knepley   }
7679566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
768731e8ddeSMatthew G. Knepley   PetscFunctionReturn(0);
769731e8ddeSMatthew G. Knepley }
770731e8ddeSMatthew G. Knepley 
7719371c9d4SSatish Balay typedef enum {
7729371c9d4SSatish Balay   CS_CARTESIAN,
7739371c9d4SSatish Balay   CS_POLAR,
7749371c9d4SSatish Balay   CS_CYLINDRICAL,
7759371c9d4SSatish Balay   CS_SPHERICAL
7769371c9d4SSatish Balay } CoordSystem;
77719ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
77819ad8254SMatthew G. Knepley 
779d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
780d71ae5a4SJacob Faibussowitsch {
78119ad8254SMatthew G. Knepley   PetscInt i;
78219ad8254SMatthew G. Knepley 
78319ad8254SMatthew G. Knepley   PetscFunctionBegin;
78419ad8254SMatthew G. Knepley   if (dim > 3) {
7859566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
78619ad8254SMatthew G. Knepley   } else {
787bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
78819ad8254SMatthew G. Knepley 
78919ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
79019ad8254SMatthew G. Knepley     switch (cs) {
7919371c9d4SSatish Balay     case CS_CARTESIAN:
7929371c9d4SSatish Balay       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
7939371c9d4SSatish Balay       break;
79419ad8254SMatthew G. Knepley     case CS_POLAR:
79563a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
79619ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
79719ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
79819ad8254SMatthew G. Knepley       break;
79919ad8254SMatthew G. Knepley     case CS_CYLINDRICAL:
80063a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
80119ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
80219ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
80319ad8254SMatthew G. Knepley       trcoords[2] = coords[2];
80419ad8254SMatthew G. Knepley       break;
80519ad8254SMatthew G. Knepley     case CS_SPHERICAL:
80663a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
80719ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
80819ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
80919ad8254SMatthew G. Knepley       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
81019ad8254SMatthew G. Knepley       break;
81119ad8254SMatthew G. Knepley     }
8129566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
81319ad8254SMatthew G. Knepley   }
81419ad8254SMatthew G. Knepley   PetscFunctionReturn(0);
81519ad8254SMatthew G. Knepley }
81619ad8254SMatthew G. Knepley 
817d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
818d71ae5a4SJacob Faibussowitsch {
819552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex *)dm->data;
8206858538eSMatthew G. Knepley   DM                cdm, cdmCell;
8216858538eSMatthew G. Knepley   PetscSection      coordSection, coordSectionCell;
8226858538eSMatthew G. Knepley   Vec               coordinates, coordinatesCell;
823552f7358SJed Brown   PetscViewerFormat format;
824552f7358SJed Brown 
825552f7358SJed Brown   PetscFunctionBegin;
8269566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
827552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
828552f7358SJed Brown     const char *name;
829f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
8309318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
831552f7358SJed Brown     PetscMPIInt rank, size;
832552f7358SJed Brown 
833*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
834*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
835*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
836*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
837*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
838*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
8399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
8409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
8419566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
8429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
8449566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
8459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
84663a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
84763a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
84863a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
84963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
8509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
85163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
852552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
853552f7358SJed Brown       PetscInt dof, off, s;
854552f7358SJed Brown 
8559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
85748a46eb9SPierre Jolivet       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
858552f7358SJed Brown     }
8599566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
86063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
86163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
862552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
863552f7358SJed Brown       PetscInt dof, off, c;
864552f7358SJed Brown 
8659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
8669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
86748a46eb9SPierre 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]));
868552f7358SJed Brown     }
8699566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
8709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8713d2e540fSStefano Zampini     if (coordSection && coordinates) {
87219ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
8736858538eSMatthew G. Knepley       const PetscScalar *array, *arrayCell = NULL;
8746858538eSMatthew G. Knepley       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
87519ad8254SMatthew G. Knepley       PetscMPIInt        rank;
87619ad8254SMatthew G. Knepley       const char        *name;
87719ad8254SMatthew G. Knepley 
8789566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
8799566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
8809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
88163a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
8829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
8836858538eSMatthew G. Knepley       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
8846858538eSMatthew G. Knepley       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
8856858538eSMatthew G. Knepley       pStart = PetscMin(pvStart, pcStart);
8866858538eSMatthew G. Knepley       pEnd   = PetscMax(pvEnd, pcEnd);
8879566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
88863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
88963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
8909566063dSJacob Faibussowitsch       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
89119ad8254SMatthew G. Knepley 
8929566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordinates, &array));
8936858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
8949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
89619ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
89719ad8254SMatthew G. Knepley         PetscInt dof, off;
89819ad8254SMatthew G. Knepley 
8996858538eSMatthew G. Knepley         if (p >= pvStart && p < pvEnd) {
9009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
9019566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
9026858538eSMatthew G. Knepley           if (dof) {
90363a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
9049566063dSJacob Faibussowitsch             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
9059566063dSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
90619ad8254SMatthew G. Knepley           }
9076858538eSMatthew G. Knepley         }
9086858538eSMatthew G. Knepley         if (cdmCell && p >= pcStart && p < pcEnd) {
9096858538eSMatthew G. Knepley           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
9106858538eSMatthew G. Knepley           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
9116858538eSMatthew G. Knepley           if (dof) {
9126858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
9136858538eSMatthew G. Knepley             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
9146858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
9156858538eSMatthew G. Knepley           }
9166858538eSMatthew G. Knepley         }
9176858538eSMatthew G. Knepley       }
9189566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
9199566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
9209566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
9216858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
9223d2e540fSStefano Zampini     }
9239566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
9249566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
9259318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
9269318fe57SMatthew G. Knepley       DMLabel     label;
9279318fe57SMatthew G. Knepley       PetscBool   isdepth;
9289318fe57SMatthew G. Knepley       const char *name;
9299318fe57SMatthew G. Knepley 
9309566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
9319566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
9329318fe57SMatthew G. Knepley       if (isdepth) continue;
9339566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
9349566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
9359318fe57SMatthew G. Knepley     }
936552f7358SJed Brown     if (size > 1) {
937552f7358SJed Brown       PetscSF sf;
938552f7358SJed Brown 
9399566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
9409566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
941552f7358SJed Brown     }
9429566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
943552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
9440588280cSMatthew G. Knepley     const char  *name, *color;
9450588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
9460588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
947fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
948552f7358SJed Brown     PetscReal    scale      = 2.0;
94978081901SStefano Zampini     PetscReal    tikzscale  = 1.0;
950b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
9510588280cSMatthew G. Knepley     double       tcoords[3];
952552f7358SJed Brown     PetscScalar *coords;
953b7f6ffafSMatthew G. Knepley     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
954552f7358SJed Brown     PetscMPIInt  rank, size;
9550588280cSMatthew G. Knepley     char       **names, **colors, **lcolors;
956b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
957fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
958fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
959552f7358SJed Brown 
960*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
961*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
962*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
963*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
964*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
965*9f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
9669566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
9689566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
9690588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
9700588280cSMatthew G. Knepley     numColors  = 10;
9710588280cSMatthew G. Knepley     numLColors = 10;
9729566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
9739566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
9749566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
9759566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
976b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
977b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
978b7f6ffafSMatthew G. Knepley     n = 4;
9799566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &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(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
9821dca8a05SBarry 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);
9839566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
9840588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
9859566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
9860588280cSMatthew G. Knepley     if (!useColors) {
9870588280cSMatthew G. Knepley       numColors = 3;
9889566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
9890588280cSMatthew G. Knepley     }
9909566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
9910588280cSMatthew G. Knepley     if (!useColors) {
9920588280cSMatthew G. Knepley       numLColors = 4;
9939566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
9940588280cSMatthew G. Knepley     }
9959566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
996b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
9979566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
9981dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
999202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
10009566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
1001fe1cc32dSStefano Zampini 
1002fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
10039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
10049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
10059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
10069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1007fe1cc32dSStefano Zampini     if (lflg) {
1008fe1cc32dSStefano Zampini       DMLabel lbl;
1009fe1cc32dSStefano Zampini 
10109566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
1011fe1cc32dSStefano Zampini       if (lbl) {
1012fe1cc32dSStefano Zampini         PetscInt val, defval;
1013fe1cc32dSStefano Zampini 
10149566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
10159566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1016fe1cc32dSStefano Zampini         for (c = pStart; c < pEnd; c++) {
1017fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
1018fe1cc32dSStefano Zampini           PetscInt  closureSize;
1019fe1cc32dSStefano Zampini 
10209566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
1021fe1cc32dSStefano Zampini           if (val == defval) continue;
1022fe1cc32dSStefano Zampini 
10239566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
102448a46eb9SPierre Jolivet           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
10259566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1026fe1cc32dSStefano Zampini         }
1027fe1cc32dSStefano Zampini       }
1028fe1cc32dSStefano Zampini     }
1029fe1cc32dSStefano Zampini 
10309566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
10319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
10329566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
10339566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
10340588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
1035552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
1036552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
1037552f7358SJed Brown \\usetikzlibrary{arrows}\n\
10385f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
10390588280cSMatthew G. Knepley     if (size > 1) {
10409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1041770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
104263a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
104363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1044770b213bSMatthew G Knepley       }
10459566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
10460588280cSMatthew G. Knepley     }
1047b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1048b7f6ffafSMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart));
1049b7f6ffafSMatthew G. Knepley 
105063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
105163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
105263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
10539566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
105463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
105563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
10569566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
105763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
105863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
105963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
106063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
10619566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1062b7f6ffafSMatthew G. Knepley     }
10639566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1064fe1cc32dSStefano Zampini 
1065552f7358SJed Brown     /* Plot vertices */
10669566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
10679566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1068552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1069552f7358SJed Brown       PetscInt  off, dof, d;
10700588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1071552f7358SJed Brown 
1072fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
10739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
10749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
10759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
107663a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
10770588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
10780588280cSMatthew G. Knepley         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1079c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
10800588280cSMatthew G. Knepley       }
10810588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
10829371c9d4SSatish Balay       if (dim == 3) {
10839371c9d4SSatish Balay         PetscReal tmp = tcoords[1];
10849371c9d4SSatish Balay         tcoords[1]    = tcoords[2];
10859371c9d4SSatish Balay         tcoords[2]    = -tmp;
10869371c9d4SSatish Balay       }
1087552f7358SJed Brown       for (d = 0; d < dof; ++d) {
10889566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
10899566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1090552f7358SJed Brown       }
1091b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0 % numColors];
1092b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
10930588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
10940588280cSMatthew G. Knepley         PetscInt val;
10959566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
10969371c9d4SSatish Balay         if (val >= 0) {
10979371c9d4SSatish Balay           color     = lcolors[l % numLColors];
10989371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
10999371c9d4SSatish Balay           break;
11009371c9d4SSatish Balay         }
11010588280cSMatthew G. Knepley       }
1102b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
110363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1104b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
110563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
11061baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1107552f7358SJed Brown     }
11089566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
11099566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1110b7f6ffafSMatthew G. Knepley     /* Plot edges */
1111b7f6ffafSMatthew G. Knepley     if (plotEdges) {
11129566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
11139566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1114b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1115b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1116b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1117b7f6ffafSMatthew G. Knepley 
1118b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
11199566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
112063a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
11219566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
11229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
11239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
11249566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
11259566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1126b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1127b7f6ffafSMatthew G. Knepley           tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1128b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1129b7f6ffafSMatthew G. Knepley         }
1130b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
11319371c9d4SSatish Balay         if (dim == 3) {
11329371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
11339371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
11349371c9d4SSatish Balay           tcoords[2]    = -tmp;
11359371c9d4SSatish Balay         }
1136b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
11379566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
11389566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1139b7f6ffafSMatthew G. Knepley         }
1140b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1 % numColors];
1141b7f6ffafSMatthew G. Knepley         else color = colors[rank % numColors];
1142b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1143b7f6ffafSMatthew G. Knepley           PetscInt val;
11449566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], v, &val));
11459371c9d4SSatish Balay           if (val >= 0) {
11469371c9d4SSatish Balay             color = lcolors[l % numLColors];
11479371c9d4SSatish Balay             break;
11489371c9d4SSatish Balay           }
1149b7f6ffafSMatthew G. Knepley         }
115063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1151b7f6ffafSMatthew G. Knepley       }
11529566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
11539566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
11549566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1155b7f6ffafSMatthew G. Knepley     }
1156846a3e8bSMatthew G. Knepley     /* Plot cells */
1157b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1158846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1159846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1160846a3e8bSMatthew G. Knepley 
1161fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1162846a3e8bSMatthew G. Knepley         color = colors[rank % numColors];
1163846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1164846a3e8bSMatthew G. Knepley           PetscInt val;
11659566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
11669371c9d4SSatish Balay           if (val >= 0) {
11679371c9d4SSatish Balay             color = lcolors[l % numLColors];
11689371c9d4SSatish Balay             break;
11699371c9d4SSatish Balay           }
1170846a3e8bSMatthew G. Knepley         }
11719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
117263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1173846a3e8bSMatthew G. Knepley       }
1174846a3e8bSMatthew G. Knepley     } else {
1175b7f6ffafSMatthew G. Knepley       DMPolytopeType ct;
1176846a3e8bSMatthew G. Knepley 
1177b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1178b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1179fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
11809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
11819371c9d4SSatish Balay         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1182b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1183b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1184b7f6ffafSMatthew G. Knepley 
11859566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
11869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1187b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1188b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1189b7f6ffafSMatthew G. Knepley 
11909566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
119163a3b9bcSJacob 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));
1192b7f6ffafSMatthew G. Knepley           }
1193b7f6ffafSMatthew G. Knepley         } else {
1194b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1195b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1196b7f6ffafSMatthew G. Knepley 
11979566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1198846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize * 2; p += 2) {
1199846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1200846a3e8bSMatthew G. Knepley 
1201b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1202846a3e8bSMatthew G. Knepley           }
12039566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1204b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1205b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v % Nv];
1206b7f6ffafSMatthew G. Knepley 
1207b7f6ffafSMatthew G. Knepley             if (v > 0) {
1208b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1209b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1210b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1211b7f6ffafSMatthew G. Knepley 
12129371c9d4SSatish Balay                 endpoints[0] = closure[v - 1];
12139371c9d4SSatish Balay                 endpoints[1] = vertex;
12149566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
121563a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
121663a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
12179566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
12181baa6e33SBarry Smith               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1219b7f6ffafSMatthew G. Knepley             }
122063a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1221b7f6ffafSMatthew G. Knepley           }
12229566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
12239566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1224846a3e8bSMatthew G. Knepley         }
1225846a3e8bSMatthew G. Knepley       }
1226b7f6ffafSMatthew G. Knepley     }
1227846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1228846a3e8bSMatthew G. Knepley       double             ccoords[3] = {0.0, 0.0, 0.0};
1229846a3e8bSMatthew G. Knepley       PetscBool          isLabeled  = PETSC_FALSE;
1230c713ec31SMatthew G. Knepley       PetscScalar       *cellCoords = NULL;
1231c713ec31SMatthew G. Knepley       const PetscScalar *array;
1232c713ec31SMatthew G. Knepley       PetscInt           numCoords, cdim, d;
1233c713ec31SMatthew G. Knepley       PetscBool          isDG;
1234846a3e8bSMatthew G. Knepley 
1235fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1236c713ec31SMatthew G. Knepley       PetscCall(DMGetCoordinateDim(dm, &cdim));
1237c713ec31SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1238c713ec31SMatthew G. Knepley       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
12399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1240c713ec31SMatthew G. Knepley       for (p = 0; p < numCoords / cdim; ++p) {
1241c713ec31SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
1242c713ec31SMatthew G. Knepley           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1243846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1244846a3e8bSMatthew G. Knepley         }
1245846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
12469371c9d4SSatish Balay         if (cdim == 3) {
12479371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
12489371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
12499371c9d4SSatish Balay           tcoords[2]    = -tmp;
12509371c9d4SSatish Balay         }
1251ad540459SPierre Jolivet         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1252846a3e8bSMatthew G. Knepley       }
1253ad540459SPierre Jolivet       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1254c713ec31SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1255c713ec31SMatthew G. Knepley       for (d = 0; d < cdim; ++d) {
12569566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
12579566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1258846a3e8bSMatthew G. Knepley       }
1259b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth % numColors];
1260b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
1261846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1262846a3e8bSMatthew G. Knepley         PetscInt val;
12639566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
12649371c9d4SSatish Balay         if (val >= 0) {
12659371c9d4SSatish Balay           color     = lcolors[l % numLColors];
12669371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
12679371c9d4SSatish Balay           break;
12689371c9d4SSatish Balay         }
1269846a3e8bSMatthew G. Knepley       }
1270b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
127163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1272b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
127363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
12741baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1275846a3e8bSMatthew G. Knepley     }
1276b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1277b7f6ffafSMatthew G. Knepley       color = colors[depth % numColors];
12789566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
12799566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
12809566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
12829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1283552f7358SJed Brown 
1284b7f6ffafSMatthew G. Knepley       color = colors[1 % numColors];
12859566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
12869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
12879566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
12899566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1290b7f6ffafSMatthew G. Knepley 
1291b7f6ffafSMatthew G. Knepley       color = colors[0 % numColors];
12929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
12939566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
12949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
12969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1297b7f6ffafSMatthew G. Knepley 
1298b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1299b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1300b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1301b7f6ffafSMatthew G. Knepley 
13029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
13039566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
130448a46eb9SPierre 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));
13050588280cSMatthew G. Knepley       }
13060588280cSMatthew G. Knepley     }
13079566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
13089566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
13099566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
131063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
13119566063dSJacob Faibussowitsch     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
13129566063dSJacob Faibussowitsch     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
13139566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
13149566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
13159566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
13160f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
13170f7d6e4aSStefano Zampini     Vec                    cown, acown;
13180f7d6e4aSStefano Zampini     VecScatter             sct;
13190f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
13200f7d6e4aSStefano Zampini     IS                     gid, acis;
13210f7d6e4aSStefano Zampini     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
13220f7d6e4aSStefano Zampini     MPI_Group              ggroup, ngroup;
13230f7d6e4aSStefano Zampini     PetscScalar           *array, nid;
13240f7d6e4aSStefano Zampini     const PetscInt        *idxs;
13250f7d6e4aSStefano Zampini     PetscInt              *idxs2, *start, *adjacency, *work;
13260f7d6e4aSStefano Zampini     PetscInt64             lm[3], gm[3];
13270f7d6e4aSStefano Zampini     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
13280f7d6e4aSStefano Zampini     PetscMPIInt            d1, d2, rank;
13290f7d6e4aSStefano Zampini 
13309566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
13319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1332b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
13339566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
13340f7d6e4aSStefano Zampini #endif
13350f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
13369566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
13379566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
13380f7d6e4aSStefano Zampini       d1 = 0;
13399566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
13400f7d6e4aSStefano Zampini       nid = d2;
13419566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
13429566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
13439566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
13440f7d6e4aSStefano Zampini     } else nid = 0.0;
13450f7d6e4aSStefano Zampini 
13460f7d6e4aSStefano Zampini     /* Get connectivity */
13479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
13489566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
13490f7d6e4aSStefano Zampini 
13500f7d6e4aSStefano Zampini     /* filter overlapped local cells */
13519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
13529566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid, &idxs));
13539566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid, &cum));
13549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &idxs2));
13550f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
13560f7d6e4aSStefano Zampini       if (idxs[c - cStart] < 0) continue;
13570f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c - cStart];
13580f7d6e4aSStefano Zampini     }
13599566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid, &idxs));
136063a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
13619566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13629566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
13630f7d6e4aSStefano Zampini 
13640f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
13659566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
13669566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
13679566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
13689566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown, &array));
13690f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
13709566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown, &array));
13719566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
13729566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
13739566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
13749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
13759566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
13769566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
13770f7d6e4aSStefano Zampini 
13780f7d6e4aSStefano Zampini     /* compute edgeCut */
13790f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
13809566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &work));
13819566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
13829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
13839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13849566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown, &array));
13850f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
13860f7d6e4aSStefano Zampini       PetscInt totl;
13870f7d6e4aSStefano Zampini 
13880f7d6e4aSStefano Zampini       totl = start[c + 1] - start[c];
13899566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
13900f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
13910f7d6e4aSStefano Zampini         if (work[i] < 0) {
13920f7d6e4aSStefano Zampini           ect += 1;
13930f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
13940f7d6e4aSStefano Zampini         }
13950f7d6e4aSStefano Zampini       }
13960f7d6e4aSStefano Zampini     }
13979566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
13989566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown, &array));
13990f7d6e4aSStefano Zampini     lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
14000f7d6e4aSStefano Zampini     lm[1] = -numVertices;
14011c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
140263a3b9bcSJacob 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]));
14030f7d6e4aSStefano Zampini     lm[0] = ect;                     /* edgeCut */
14040f7d6e4aSStefano Zampini     lm[1] = ectn;                    /* node-aware edgeCut */
14050f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
14061c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
140763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1408b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
140963a3b9bcSJacob 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.));
14100f7d6e4aSStefano Zampini #else
141163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
14120f7d6e4aSStefano Zampini #endif
14139566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
14149566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
14159566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
14169566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1417552f7358SJed Brown   } else {
1418412e9a14SMatthew G. Knepley     const char    *name;
1419d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1420412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1421d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1422ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
14239318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1424412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1425412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1426552f7358SJed Brown 
14279566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
14289566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
14299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
14309566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
14319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
14329566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
143363a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
143463a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
143563a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
14369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
14371c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
14389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd));
1439d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
14409566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
14419566063dSJacob Faibussowitsch     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1442412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1443412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1444412e9a14SMatthew G. Knepley 
14459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
14469566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1447412e9a14SMatthew G. Knepley       ict = ct0;
14489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1449412e9a14SMatthew G. Knepley       ct0 = (DMPolytopeType)ict;
1450412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1451412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1452412e9a14SMatthew G. Knepley 
14539566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1454412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1455412e9a14SMatthew G. Knepley         else ++Nc[1];
1456412e9a14SMatthew G. Knepley       }
1457ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
14589566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
14599566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
14609566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
146163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1462834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1463dd400576SPatrick Sanan           if (rank == 0) {
146463a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
146563a3b9bcSJacob Faibussowitsch             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
146663a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1467834065abSMatthew G. Knepley           }
1468cbb7f117SMark Adams         }
1469ca7bf7eeSMatthew G. Knepley       } else {
1470ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1471ca7bf7eeSMatthew G. Knepley 
14729371c9d4SSatish Balay         locMinMax[0] = Nc[0] + Nc[1];
14739371c9d4SSatish Balay         locMinMax[1] = Nc[0] + Nc[1];
14749566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
14759371c9d4SSatish Balay         locMinMax[0] = Nc[1];
14769371c9d4SSatish Balay         locMinMax[1] = Nc[1];
14779566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1478ca7bf7eeSMatthew G. Knepley         if (d == depth) {
14799371c9d4SSatish Balay           locMinMax[0] = gcNum;
14809371c9d4SSatish Balay           locMinMax[1] = gcNum;
14819566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1482ca7bf7eeSMatthew G. Knepley         }
148363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
14849566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
14859566063dSJacob Faibussowitsch         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
14869566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1487ca7bf7eeSMatthew G. Knepley       }
14889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1489552f7358SJed Brown     }
14909566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
14919318fe57SMatthew G. Knepley     {
14929318fe57SMatthew G. Knepley       const PetscReal *maxCell;
14939318fe57SMatthew G. Knepley       const PetscReal *L;
14946858538eSMatthew G. Knepley       PetscBool        localized;
14959318fe57SMatthew G. Knepley 
14964fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
14979566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
14986858538eSMatthew G. Knepley       if (L || localized) {
14996858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
15009566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
15016858538eSMatthew G. Knepley         if (L) {
15026858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
15039318fe57SMatthew G. Knepley           for (d = 0; d < dim; ++d) {
15046858538eSMatthew G. Knepley             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
15056858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
15069318fe57SMatthew G. Knepley           }
15076858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
15086858538eSMatthew G. Knepley         }
15096858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
15109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
15119318fe57SMatthew G. Knepley       }
15129318fe57SMatthew G. Knepley     }
15139566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
15149566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1515a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1516a57dd577SMatthew G Knepley       DMLabel         label;
1517a57dd577SMatthew G Knepley       const char     *name;
1518a57dd577SMatthew G Knepley       IS              valueIS;
1519a57dd577SMatthew G Knepley       const PetscInt *values;
1520a57dd577SMatthew G Knepley       PetscInt        numValues, v;
1521a57dd577SMatthew G Knepley 
15229566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
15239566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
15249566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
152563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
15269566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValueIS(label, &valueIS));
15279566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(valueIS, &values));
15289566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1529a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1530a57dd577SMatthew G Knepley         PetscInt size;
1531a57dd577SMatthew G Knepley 
15329566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
15339566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
153463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1535a57dd577SMatthew G Knepley       }
15369566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
15379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
15389566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(valueIS, &values));
15399566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&valueIS));
1540a57dd577SMatthew G Knepley     }
1541c1cad2e7SMatthew G. Knepley     {
1542c1cad2e7SMatthew G. Knepley       char    **labelNames;
1543c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1544c1cad2e7SMatthew G. Knepley       PetscBool flg;
1545c1cad2e7SMatthew G. Knepley 
15469566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
15479566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1548c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1549c1cad2e7SMatthew G. Knepley         DMLabel label;
1550c1cad2e7SMatthew G. Knepley 
15519566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1552c1cad2e7SMatthew G. Knepley         if (flg) {
15539566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
15549566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1555c1cad2e7SMatthew G. Knepley         }
15569566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1557c1cad2e7SMatthew G. Knepley       }
15589566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1559c1cad2e7SMatthew G. Knepley     }
156034aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
156134aa8a36SMatthew G. Knepley     if (dm->Nf) {
156234aa8a36SMatthew G. Knepley       PetscInt f;
156334aa8a36SMatthew G. Knepley 
156434aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
156534aa8a36SMatthew G. Knepley         const char *name;
156634aa8a36SMatthew G. Knepley 
15679566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
15689566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
15699566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
15709566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
157134aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
15729566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
15739566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
157434aa8a36SMatthew G. Knepley         } else {
15759566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
15769566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
157734aa8a36SMatthew G. Knepley         }
15789566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
157934aa8a36SMatthew G. Knepley       }
158034aa8a36SMatthew G. Knepley     }
15819566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
15828e7ff633SMatthew G. Knepley     if (cdm) {
15839566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
1584*9f4ada15SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
15859566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
15869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
15878e7ff633SMatthew G. Knepley     }
1588552f7358SJed Brown   }
1589552f7358SJed Brown   PetscFunctionReturn(0);
1590552f7358SJed Brown }
1591552f7358SJed Brown 
1592d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1593d71ae5a4SJacob Faibussowitsch {
1594e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1595e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1596a12d352dSMatthew G. Knepley   PetscInt       cdim;
1597e5c487bfSMatthew G. Knepley 
1598e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
15999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
16009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
16019566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1602e5c487bfSMatthew G. Knepley   switch (ct) {
1603a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1604a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1605a12d352dSMatthew G. Knepley     switch (cdim) {
16069371c9d4SSatish Balay     case 1: {
1607a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1608a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1609a12d352dSMatthew G. Knepley 
16109566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
16119566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
16129566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
16139371c9d4SSatish Balay     } break;
16149371c9d4SSatish Balay     case 2: {
1615a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1616a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1617a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1618a12d352dSMatthew G. Knepley 
16199566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16209566063dSJacob 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));
16219566063dSJacob 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));
16229371c9d4SSatish Balay     } break;
1623d71ae5a4SJacob Faibussowitsch     default:
1624d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1625a12d352dSMatthew G. Knepley     }
1626a12d352dSMatthew G. Knepley     break;
1627e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
16289371c9d4SSatish 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));
16299566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16309566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
16319566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1632e5c487bfSMatthew G. Knepley     break;
1633e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
16349371c9d4SSatish 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));
16359371c9d4SSatish 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));
16369566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
16379566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
16389566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
16399566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1640e5c487bfSMatthew G. Knepley     break;
1641*9f4ada15SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1642*9f4ada15SMatthew 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));
1643*9f4ada15SMatthew 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));
1644*9f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1645*9f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1646*9f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1647*9f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1648*9f4ada15SMatthew G. Knepley     break;
1649d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_FV_GHOST:
1650d71ae5a4SJacob Faibussowitsch     break;
1651d71ae5a4SJacob Faibussowitsch   default:
1652d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1653e5c487bfSMatthew G. Knepley   }
1654e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
1655e5c487bfSMatthew G. Knepley }
1656e5c487bfSMatthew G. Knepley 
1657d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1658d71ae5a4SJacob Faibussowitsch {
1659e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1660e5c487bfSMatthew G. Knepley   PetscReal      centroid[2] = {0., 0.};
1661e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1662e5c487bfSMatthew G. Knepley   PetscInt       fillColor, v, e, d;
1663e5c487bfSMatthew G. Knepley 
1664e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
16659566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
16669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1667e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1668e5c487bfSMatthew G. Knepley   switch (ct) {
16699371c9d4SSatish Balay   case DM_POLYTOPE_TRIANGLE: {
1670e5c487bfSMatthew G. Knepley     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1671e5c487bfSMatthew G. Knepley 
16729371c9d4SSatish Balay     for (v = 0; v < 3; ++v) {
16739371c9d4SSatish Balay       centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.;
16749371c9d4SSatish Balay       centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.;
16759371c9d4SSatish Balay     }
1676e5c487bfSMatthew G. Knepley     for (e = 0; e < 3; ++e) {
1677e5c487bfSMatthew G. Knepley       refCoords[0] = refVertices[e * 2 + 0];
1678e5c487bfSMatthew G. Knepley       refCoords[1] = refVertices[e * 2 + 1];
1679e5c487bfSMatthew G. Knepley       for (d = 1; d <= edgeDiv; ++d) {
1680e5c487bfSMatthew G. Knepley         refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv;
1681e5c487bfSMatthew G. Knepley         refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv;
1682e5c487bfSMatthew G. Knepley       }
16839566063dSJacob Faibussowitsch       PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1684e5c487bfSMatthew G. Knepley       for (d = 0; d < edgeDiv; ++d) {
16859566063dSJacob 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));
16869566063dSJacob 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));
1687e5c487bfSMatthew G. Knepley       }
1688e5c487bfSMatthew G. Knepley     }
16899371c9d4SSatish Balay   } break;
1690d71ae5a4SJacob Faibussowitsch   default:
1691d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1692e5c487bfSMatthew G. Knepley   }
1693e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
1694e5c487bfSMatthew G. Knepley }
1695e5c487bfSMatthew G. Knepley 
1696d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1697d71ae5a4SJacob Faibussowitsch {
1698e412dcbdSMatthew G. Knepley   PetscDraw          draw;
1699e412dcbdSMatthew G. Knepley   DM                 cdm;
1700e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
1701e412dcbdSMatthew G. Knepley   Vec                coordinates;
1702e412dcbdSMatthew G. Knepley   const PetscScalar *coords;
170329494db1SLisandro Dalcin   PetscReal          xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1704e5c487bfSMatthew G. Knepley   PetscReal         *refCoords, *edgeCoords;
1705e5c487bfSMatthew G. Knepley   PetscBool          isnull, drawAffine = PETSC_TRUE;
1706e5c487bfSMatthew G. Knepley   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1707e412dcbdSMatthew G. Knepley 
1708e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
17099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
171063a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
17119566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
17129566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
17139566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
17149566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
17159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
17169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
17179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1718e412dcbdSMatthew G. Knepley 
17199566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
17209566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
1721e412dcbdSMatthew G. Knepley   if (isnull) PetscFunctionReturn(0);
17229566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1723e412dcbdSMatthew G. Knepley 
17249566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
17259566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
1726e412dcbdSMatthew G. Knepley   for (c = 0; c < N; c += dim) {
17279371c9d4SSatish Balay     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));
17289371c9d4SSatish Balay     bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
17299371c9d4SSatish Balay     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1]));
17309371c9d4SSatish Balay     bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1]));
1731e412dcbdSMatthew G. Knepley   }
17329566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
17331c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm)));
17341c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm)));
17359566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
17369566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1737e412dcbdSMatthew G. Knepley 
1738cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1739cf3064d3SMatthew G. Knepley     PetscScalar *coords = NULL;
1740ba2698f1SMatthew G. Knepley     PetscInt     numCoords;
1741cf3064d3SMatthew G. Knepley 
17429566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords));
17431baa6e33SBarry Smith     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
17441baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
17459566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
1746cf3064d3SMatthew G. Knepley   }
17479566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
17489566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
17499566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
17509566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
1751e412dcbdSMatthew G. Knepley   PetscFunctionReturn(0);
1752e412dcbdSMatthew G. Knepley }
1753e412dcbdSMatthew G. Knepley 
17541e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
17551e50132fSMatthew G. Knepley   #include <exodusII.h>
17566823f3c5SBlaise Bourdin   #include <petscviewerexodusii.h>
17571e50132fSMatthew G. Knepley #endif
17581e50132fSMatthew G. Knepley 
1759d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1760d71ae5a4SJacob Faibussowitsch {
17615f34f2dcSJed Brown   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1762002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
1763552f7358SJed Brown 
1764552f7358SJed Brown   PetscFunctionBegin;
1765552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1766552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
17679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
17689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
17699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
17709566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
17719566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
17729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
17735f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1774552f7358SJed Brown   if (iascii) {
17758135c375SStefano Zampini     PetscViewerFormat format;
17769566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
17771baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
17781baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
1779c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1780c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
17819566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1782c6ccd67eSMatthew G. Knepley #else
1783c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1784552f7358SJed Brown #endif
1785e412dcbdSMatthew G. Knepley   } else if (isvtk) {
17869566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1787e412dcbdSMatthew G. Knepley   } else if (isdraw) {
17889566063dSJacob Faibussowitsch     PetscCall(DMPlexView_Draw(dm, viewer));
17898135c375SStefano Zampini   } else if (isglvis) {
17909566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
17911e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
17921e50132fSMatthew G. Knepley   } else if (isexodus) {
17936823f3c5SBlaise Bourdin     /*
17946823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
17956823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
17966823f3c5SBlaise Bourdin       with ID 1, containig all cells.
17976823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
17986823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
17996823f3c5SBlaise Bourdin     */
18006823f3c5SBlaise Bourdin     PetscInt numCS;
18019566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
18026823f3c5SBlaise Bourdin     if (!numCS) {
18031e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
18049566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
18059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
18069566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
18076823f3c5SBlaise Bourdin     }
18089566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
18091e50132fSMatthew G. Knepley #endif
18105f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
18115f34f2dcSJed Brown   } else if (iscgns) {
18125f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
18135f34f2dcSJed Brown #endif
18141baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1815cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
18169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1817cb3ba0daSMatthew G. Knepley   if (flg) {
1818cb3ba0daSMatthew G. Knepley     Vec ranks;
18199566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
18209566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
18219566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
1822cb3ba0daSMatthew G. Knepley   }
1823002a2709SMatthew G. Knepley   /* Optionally view a label */
18249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1825002a2709SMatthew G. Knepley   if (flg) {
1826002a2709SMatthew G. Knepley     DMLabel label;
1827002a2709SMatthew G. Knepley     Vec     val;
1828002a2709SMatthew G. Knepley 
18299566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
183028b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
18319566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
18329566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
18339566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
1834002a2709SMatthew G. Knepley   }
1835552f7358SJed Brown   PetscFunctionReturn(0);
1836552f7358SJed Brown }
1837552f7358SJed Brown 
18387f96f51bSksagiyam /*@
18397f96f51bSksagiyam   DMPlexTopologyView - Saves a DMPlex topology into a file
18407f96f51bSksagiyam 
18417f96f51bSksagiyam   Collective on DM
18427f96f51bSksagiyam 
18437f96f51bSksagiyam   Input Parameters:
18447f96f51bSksagiyam + dm                - The DM whose topology is to be saved
18457f96f51bSksagiyam - viewer            - The PetscViewer for saving
18467f96f51bSksagiyam 
18477f96f51bSksagiyam   Level: advanced
18487f96f51bSksagiyam 
1849db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`
18507f96f51bSksagiyam @*/
1851d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1852d71ae5a4SJacob Faibussowitsch {
18537f96f51bSksagiyam   PetscBool ishdf5;
18547f96f51bSksagiyam 
18557f96f51bSksagiyam   PetscFunctionBegin;
18567f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
18577f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
18599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
18607f96f51bSksagiyam   if (ishdf5) {
18617f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
18627f96f51bSksagiyam     PetscViewerFormat format;
18639566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
18647f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18657f96f51bSksagiyam       IS globalPointNumbering;
18667f96f51bSksagiyam 
18679566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
18689566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
18699566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
187098921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
18717f96f51bSksagiyam #else
18727f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
18737f96f51bSksagiyam #endif
18747f96f51bSksagiyam   }
18759566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
18767f96f51bSksagiyam   PetscFunctionReturn(0);
18777f96f51bSksagiyam }
18787f96f51bSksagiyam 
187977b8e257Sksagiyam /*@
188077b8e257Sksagiyam   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
188177b8e257Sksagiyam 
188277b8e257Sksagiyam   Collective on DM
188377b8e257Sksagiyam 
188477b8e257Sksagiyam   Input Parameters:
188577b8e257Sksagiyam + dm     - The DM whose coordinates are to be saved
188677b8e257Sksagiyam - viewer - The PetscViewer for saving
188777b8e257Sksagiyam 
188877b8e257Sksagiyam   Level: advanced
188977b8e257Sksagiyam 
1890db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`
189177b8e257Sksagiyam @*/
1892d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1893d71ae5a4SJacob Faibussowitsch {
189477b8e257Sksagiyam   PetscBool ishdf5;
189577b8e257Sksagiyam 
189677b8e257Sksagiyam   PetscFunctionBegin;
189777b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
189877b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
190177b8e257Sksagiyam   if (ishdf5) {
190277b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
190377b8e257Sksagiyam     PetscViewerFormat format;
19049566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
190577b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
19069566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
1907fe28d297SMatthew Knepley     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
190877b8e257Sksagiyam #else
190977b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
191077b8e257Sksagiyam #endif
191177b8e257Sksagiyam   }
19129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
191377b8e257Sksagiyam   PetscFunctionReturn(0);
191477b8e257Sksagiyam }
191577b8e257Sksagiyam 
1916bd6565f1Sksagiyam /*@
1917bd6565f1Sksagiyam   DMPlexLabelsView - Saves DMPlex labels into a file
1918bd6565f1Sksagiyam 
1919bd6565f1Sksagiyam   Collective on DM
1920bd6565f1Sksagiyam 
1921bd6565f1Sksagiyam   Input Parameters:
1922bd6565f1Sksagiyam + dm     - The DM whose labels are to be saved
1923bd6565f1Sksagiyam - viewer - The PetscViewer for saving
1924bd6565f1Sksagiyam 
1925bd6565f1Sksagiyam   Level: advanced
1926bd6565f1Sksagiyam 
1927db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`
1928bd6565f1Sksagiyam @*/
1929d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1930d71ae5a4SJacob Faibussowitsch {
1931bd6565f1Sksagiyam   PetscBool ishdf5;
1932bd6565f1Sksagiyam 
1933bd6565f1Sksagiyam   PetscFunctionBegin;
1934bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1935bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
1938bd6565f1Sksagiyam   if (ishdf5) {
1939bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
1940bd6565f1Sksagiyam     IS                globalPointNumbering;
1941bd6565f1Sksagiyam     PetscViewerFormat format;
1942bd6565f1Sksagiyam 
19439566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
1944bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
19459566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
19469566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
19479566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
194898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1949bd6565f1Sksagiyam #else
1950bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1951bd6565f1Sksagiyam #endif
1952bd6565f1Sksagiyam   }
19539566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
1954bd6565f1Sksagiyam   PetscFunctionReturn(0);
1955bd6565f1Sksagiyam }
1956bd6565f1Sksagiyam 
1957021affd3Sksagiyam /*@
1958021affd3Sksagiyam   DMPlexSectionView - Saves a section associated with a DMPlex
1959021affd3Sksagiyam 
1960021affd3Sksagiyam   Collective on DM
1961021affd3Sksagiyam 
1962021affd3Sksagiyam   Input Parameters:
1963021affd3Sksagiyam + dm         - The DM that contains the topology on which the section to be saved is defined
1964021affd3Sksagiyam . viewer     - The PetscViewer for saving
1965021affd3Sksagiyam - sectiondm  - The DM that contains the section to be saved
1966021affd3Sksagiyam 
1967021affd3Sksagiyam   Level: advanced
1968021affd3Sksagiyam 
1969021affd3Sksagiyam   Notes:
1970021affd3Sksagiyam   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.
1971021affd3Sksagiyam 
1972021affd3Sksagiyam   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.
1973021affd3Sksagiyam 
1974db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`
1975021affd3Sksagiyam @*/
1976d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1977d71ae5a4SJacob Faibussowitsch {
1978021affd3Sksagiyam   PetscBool ishdf5;
1979021affd3Sksagiyam 
1980021affd3Sksagiyam   PetscFunctionBegin;
1981021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1982021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1983021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
19849566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
1986021affd3Sksagiyam   if (ishdf5) {
1987021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
19889566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1989021affd3Sksagiyam #else
1990021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1991021affd3Sksagiyam #endif
1992021affd3Sksagiyam   }
19939566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
1994021affd3Sksagiyam   PetscFunctionReturn(0);
1995021affd3Sksagiyam }
1996021affd3Sksagiyam 
19973e97647fSksagiyam /*@
19983e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
19993e97647fSksagiyam 
20003e97647fSksagiyam   Collective on DM
20013e97647fSksagiyam 
20023e97647fSksagiyam   Input Parameters:
20033e97647fSksagiyam + dm        - The DM that represents the topology
20043e97647fSksagiyam . viewer    - The PetscViewer to save data with
20053e97647fSksagiyam . sectiondm - The DM that contains the global section on which vec is defined
20063e97647fSksagiyam - vec       - The global vector to be saved
20073e97647fSksagiyam 
20083e97647fSksagiyam   Level: advanced
20093e97647fSksagiyam 
20103e97647fSksagiyam   Notes:
20113e97647fSksagiyam   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.
20123e97647fSksagiyam 
20133e97647fSksagiyam   Typical calling sequence
20143e97647fSksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
20153e97647fSksagiyam $       DMSetType(dm, DMPLEX);
20163e97647fSksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
20173e97647fSksagiyam $       DMClone(dm, &sectiondm);
20183e97647fSksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
20193e97647fSksagiyam $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
20203e97647fSksagiyam $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
20213e97647fSksagiyam $       PetscSectionSetChart(section, pStart, pEnd);
20223e97647fSksagiyam $       PetscSectionSetUp(section);
20233e97647fSksagiyam $       DMSetLocalSection(sectiondm, section);
20243e97647fSksagiyam $       PetscSectionDestroy(&section);
20253e97647fSksagiyam $       DMGetGlobalVector(sectiondm, &vec);
20263e97647fSksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
20273e97647fSksagiyam $       DMPlexTopologyView(dm, viewer);
20283e97647fSksagiyam $       DMPlexSectionView(dm, viewer, sectiondm);
20293e97647fSksagiyam $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
20303e97647fSksagiyam $       DMRestoreGlobalVector(sectiondm, &vec);
20313e97647fSksagiyam $       DMDestroy(&sectiondm);
20323e97647fSksagiyam $       DMDestroy(&dm);
20333e97647fSksagiyam 
2034db781477SPatrick Sanan .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
20353e97647fSksagiyam @*/
2036d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2037d71ae5a4SJacob Faibussowitsch {
20383e97647fSksagiyam   PetscBool ishdf5;
20393e97647fSksagiyam 
20403e97647fSksagiyam   PetscFunctionBegin;
20413e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20423e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20433e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
20443e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
20453e97647fSksagiyam   /* Check consistency */
20463e97647fSksagiyam   {
20473e97647fSksagiyam     PetscSection section;
20483e97647fSksagiyam     PetscBool    includesConstraints;
20493e97647fSksagiyam     PetscInt     m, m1;
20503e97647fSksagiyam 
20519566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
20529566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
20539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
20549566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
20559566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
205663a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
20573e97647fSksagiyam   }
20589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
20603e97647fSksagiyam   if (ishdf5) {
20613e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
20629566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
20633e97647fSksagiyam #else
20643e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20653e97647fSksagiyam #endif
20663e97647fSksagiyam   }
20679566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
20683e97647fSksagiyam   PetscFunctionReturn(0);
20693e97647fSksagiyam }
20703e97647fSksagiyam 
20713e97647fSksagiyam /*@
20723e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
20733e97647fSksagiyam 
20743e97647fSksagiyam   Collective on DM
20753e97647fSksagiyam 
20763e97647fSksagiyam   Input Parameters:
20773e97647fSksagiyam + dm        - The DM that represents the topology
20783e97647fSksagiyam . viewer    - The PetscViewer to save data with
20793e97647fSksagiyam . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
20803e97647fSksagiyam - vec       - The local vector to be saved
20813e97647fSksagiyam 
20823e97647fSksagiyam   Level: advanced
20833e97647fSksagiyam 
20843e97647fSksagiyam   Notes:
20853e97647fSksagiyam   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.
20863e97647fSksagiyam 
20873e97647fSksagiyam   Typical calling sequence
20883e97647fSksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
20893e97647fSksagiyam $       DMSetType(dm, DMPLEX);
20903e97647fSksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
20913e97647fSksagiyam $       DMClone(dm, &sectiondm);
20923e97647fSksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
20933e97647fSksagiyam $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
20943e97647fSksagiyam $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
20953e97647fSksagiyam $       PetscSectionSetChart(section, pStart, pEnd);
20963e97647fSksagiyam $       PetscSectionSetUp(section);
20973e97647fSksagiyam $       DMSetLocalSection(sectiondm, section);
20983e97647fSksagiyam $       DMGetLocalVector(sectiondm, &vec);
20993e97647fSksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
21003e97647fSksagiyam $       DMPlexTopologyView(dm, viewer);
21013e97647fSksagiyam $       DMPlexSectionView(dm, viewer, sectiondm);
21023e97647fSksagiyam $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
21033e97647fSksagiyam $       DMRestoreLocalVector(sectiondm, &vec);
21043e97647fSksagiyam $       DMDestroy(&sectiondm);
21053e97647fSksagiyam $       DMDestroy(&dm);
21063e97647fSksagiyam 
2107db781477SPatrick Sanan .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
21083e97647fSksagiyam @*/
2109d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2110d71ae5a4SJacob Faibussowitsch {
21113e97647fSksagiyam   PetscBool ishdf5;
21123e97647fSksagiyam 
21133e97647fSksagiyam   PetscFunctionBegin;
21143e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21153e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21163e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
21173e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
21183e97647fSksagiyam   /* Check consistency */
21193e97647fSksagiyam   {
21203e97647fSksagiyam     PetscSection section;
21213e97647fSksagiyam     PetscBool    includesConstraints;
21223e97647fSksagiyam     PetscInt     m, m1;
21233e97647fSksagiyam 
21249566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
21259566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
21269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
21279566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
21289566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
212963a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
21303e97647fSksagiyam   }
21319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21329566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
21333e97647fSksagiyam   if (ishdf5) {
21343e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
21359566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
21363e97647fSksagiyam #else
21373e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
21383e97647fSksagiyam #endif
21393e97647fSksagiyam   }
21409566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
21413e97647fSksagiyam   PetscFunctionReturn(0);
21423e97647fSksagiyam }
21433e97647fSksagiyam 
2144d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2145d71ae5a4SJacob Faibussowitsch {
2146d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
21472c40f234SMatthew G. Knepley 
21482c40f234SMatthew G. Knepley   PetscFunctionBegin;
21492c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21502c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2152d4f5a9a0SVaclav Hapla   if (ishdf5) {
21532c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
21549c48423bSVaclav Hapla     PetscViewerFormat format;
21559566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
21569c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
21579566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2158509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21599566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
216098921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2161b458e8f1SJose E. Roman     PetscFunctionReturn(0);
21622c40f234SMatthew G. Knepley #else
21632c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2164552f7358SJed Brown #endif
216598921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2166552f7358SJed Brown }
2167552f7358SJed Brown 
2168ea8e1828Sksagiyam /*@
2169ea8e1828Sksagiyam   DMPlexTopologyLoad - Loads a topology into a DMPlex
2170ea8e1828Sksagiyam 
2171ea8e1828Sksagiyam   Collective on DM
2172ea8e1828Sksagiyam 
2173ea8e1828Sksagiyam   Input Parameters:
2174ea8e1828Sksagiyam + dm                - The DM into which the topology is loaded
2175ea8e1828Sksagiyam - viewer            - The PetscViewer for the saved topology
2176ea8e1828Sksagiyam 
2177dec9e869Sksagiyam   Output Parameters:
2178f84dd6b4Sksagiyam . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded
2179dec9e869Sksagiyam 
2180ea8e1828Sksagiyam   Level: advanced
2181ea8e1828Sksagiyam 
2182db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
2183ea8e1828Sksagiyam @*/
2184d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2185d71ae5a4SJacob Faibussowitsch {
2186ea8e1828Sksagiyam   PetscBool ishdf5;
2187ea8e1828Sksagiyam 
2188ea8e1828Sksagiyam   PetscFunctionBegin;
2189ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2190ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2191f84dd6b4Sksagiyam   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
21929566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21939566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2194ea8e1828Sksagiyam   if (ishdf5) {
2195ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2196ea8e1828Sksagiyam     PetscViewerFormat format;
21979566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2198ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21999566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
220098921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2201ea8e1828Sksagiyam #else
2202ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2203ea8e1828Sksagiyam #endif
2204ea8e1828Sksagiyam   }
22059566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2206ea8e1828Sksagiyam   PetscFunctionReturn(0);
2207ea8e1828Sksagiyam }
2208ea8e1828Sksagiyam 
22093e701f1cSksagiyam /*@
22103e701f1cSksagiyam   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
22113e701f1cSksagiyam 
22123e701f1cSksagiyam   Collective on DM
22133e701f1cSksagiyam 
22143e701f1cSksagiyam   Input Parameters:
22153e701f1cSksagiyam + dm     - The DM into which the coordinates are loaded
2216c9ad657eSksagiyam . viewer - The PetscViewer for the saved coordinates
2217c9ad657eSksagiyam - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
22183e701f1cSksagiyam 
22193e701f1cSksagiyam   Level: advanced
22203e701f1cSksagiyam 
2221db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
22223e701f1cSksagiyam @*/
2223d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2224d71ae5a4SJacob Faibussowitsch {
22253e701f1cSksagiyam   PetscBool ishdf5;
22263e701f1cSksagiyam 
22273e701f1cSksagiyam   PetscFunctionBegin;
22283e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22293e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2230c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
22319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22329566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
22333e701f1cSksagiyam   if (ishdf5) {
22343e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
22353e701f1cSksagiyam     PetscViewerFormat format;
22369566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
22373e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
22389566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
223998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
22403e701f1cSksagiyam #else
22413e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
22423e701f1cSksagiyam #endif
22433e701f1cSksagiyam   }
22449566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
22453e701f1cSksagiyam   PetscFunctionReturn(0);
22463e701f1cSksagiyam }
22473e701f1cSksagiyam 
2248b08ad5deSksagiyam /*@
2249b08ad5deSksagiyam   DMPlexLabelsLoad - Loads labels into a DMPlex
2250b08ad5deSksagiyam 
2251b08ad5deSksagiyam   Collective on DM
2252b08ad5deSksagiyam 
2253b08ad5deSksagiyam   Input Parameters:
2254b08ad5deSksagiyam + dm     - The DM into which the labels are loaded
2255e6368b79SVaclav Hapla . viewer - The PetscViewer for the saved labels
2256e6368b79SVaclav Hapla - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2257b08ad5deSksagiyam 
2258b08ad5deSksagiyam   Level: advanced
2259b08ad5deSksagiyam 
2260e6368b79SVaclav Hapla   Notes:
2261e6368b79SVaclav Hapla   The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs.
2262e6368b79SVaclav Hapla 
2263db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
2264b08ad5deSksagiyam @*/
2265d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2266d71ae5a4SJacob Faibussowitsch {
2267b08ad5deSksagiyam   PetscBool ishdf5;
2268b08ad5deSksagiyam 
2269b08ad5deSksagiyam   PetscFunctionBegin;
2270b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2271b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2272e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2275b08ad5deSksagiyam   if (ishdf5) {
2276b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2277b08ad5deSksagiyam     PetscViewerFormat format;
2278b08ad5deSksagiyam 
22799566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2280b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
22819566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
228298921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2283b08ad5deSksagiyam #else
2284b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2285b08ad5deSksagiyam #endif
2286b08ad5deSksagiyam   }
22879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2288b08ad5deSksagiyam   PetscFunctionReturn(0);
2289b08ad5deSksagiyam }
2290b08ad5deSksagiyam 
2291f84dd6b4Sksagiyam /*@
2292f84dd6b4Sksagiyam   DMPlexSectionLoad - Loads section into a DMPlex
2293f84dd6b4Sksagiyam 
2294f84dd6b4Sksagiyam   Collective on DM
2295f84dd6b4Sksagiyam 
2296f84dd6b4Sksagiyam   Input Parameters:
2297f84dd6b4Sksagiyam + dm          - The DM that represents the topology
2298f84dd6b4Sksagiyam . viewer      - The PetscViewer that represents the on-disk section (sectionA)
2299f84dd6b4Sksagiyam . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2300f84dd6b4Sksagiyam - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2301f84dd6b4Sksagiyam 
2302f84dd6b4Sksagiyam   Output Parameters
2303f84dd6b4Sksagiyam + globalDofSF - The SF 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)
2304f84dd6b4Sksagiyam - localDofSF  - The SF 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)
2305f84dd6b4Sksagiyam 
2306f84dd6b4Sksagiyam   Level: advanced
2307f84dd6b4Sksagiyam 
2308f84dd6b4Sksagiyam   Notes:
2309f84dd6b4Sksagiyam   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.
2310f84dd6b4Sksagiyam 
2311f84dd6b4Sksagiyam   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.
2312f84dd6b4Sksagiyam 
2313f84dd6b4Sksagiyam   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.
2314f84dd6b4Sksagiyam 
2315f84dd6b4Sksagiyam   Example using 2 processes:
2316f84dd6b4Sksagiyam $  NX (number of points on dm): 4
2317f84dd6b4Sksagiyam $  sectionA                   : the on-disk section
2318f84dd6b4Sksagiyam $  vecA                       : a vector associated with sectionA
2319f84dd6b4Sksagiyam $  sectionB                   : sectiondm's local section constructed in this function
2320f84dd6b4Sksagiyam $  vecB (local)               : a vector associated with sectiondm's local section
2321f84dd6b4Sksagiyam $  vecB (global)              : a vector associated with sectiondm's global section
2322f84dd6b4Sksagiyam $
2323f84dd6b4Sksagiyam $                                     rank 0    rank 1
2324f84dd6b4Sksagiyam $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2325f84dd6b4Sksagiyam $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2326f84dd6b4Sksagiyam $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2327f84dd6b4Sksagiyam $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2328f84dd6b4Sksagiyam $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2329f84dd6b4Sksagiyam $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2330f84dd6b4Sksagiyam $  sectionB->atlasDof             :     1 0 1 | 1 3
2331f84dd6b4Sksagiyam $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2332f84dd6b4Sksagiyam $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2333f84dd6b4Sksagiyam $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2334f84dd6b4Sksagiyam $
2335f84dd6b4Sksagiyam $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2336f84dd6b4Sksagiyam 
2337db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`
2338f84dd6b4Sksagiyam @*/
2339d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2340d71ae5a4SJacob Faibussowitsch {
2341f84dd6b4Sksagiyam   PetscBool ishdf5;
2342f84dd6b4Sksagiyam 
2343f84dd6b4Sksagiyam   PetscFunctionBegin;
2344f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2345f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2346f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2347f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2348f84dd6b4Sksagiyam   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2349f84dd6b4Sksagiyam   if (localDofSF) PetscValidPointer(localDofSF, 6);
23509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23519566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2352f84dd6b4Sksagiyam   if (ishdf5) {
2353f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
23549566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2355f84dd6b4Sksagiyam #else
2356f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2357f84dd6b4Sksagiyam #endif
2358f84dd6b4Sksagiyam   }
23599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2360f84dd6b4Sksagiyam   PetscFunctionReturn(0);
2361f84dd6b4Sksagiyam }
2362f84dd6b4Sksagiyam 
23638be3dfe1Sksagiyam /*@
23648be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
23658be3dfe1Sksagiyam 
23668be3dfe1Sksagiyam   Collective on DM
23678be3dfe1Sksagiyam 
23688be3dfe1Sksagiyam   Input Parameters:
23698be3dfe1Sksagiyam + dm        - The DM that represents the topology
23708be3dfe1Sksagiyam . viewer    - The PetscViewer that represents the on-disk vector data
23718be3dfe1Sksagiyam . sectiondm - The DM that contains the global section on which vec is defined
23728be3dfe1Sksagiyam . sf        - The SF that migrates the on-disk vector data into vec
23738be3dfe1Sksagiyam - vec       - The global vector to set values of
23748be3dfe1Sksagiyam 
23758be3dfe1Sksagiyam   Level: advanced
23768be3dfe1Sksagiyam 
23778be3dfe1Sksagiyam   Notes:
23788be3dfe1Sksagiyam   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.
23798be3dfe1Sksagiyam 
23808be3dfe1Sksagiyam   Typical calling sequence
23818be3dfe1Sksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
23828be3dfe1Sksagiyam $       DMSetType(dm, DMPLEX);
23838be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
23848be3dfe1Sksagiyam $       DMPlexTopologyLoad(dm, viewer, &sfX);
23858be3dfe1Sksagiyam $       DMClone(dm, &sectiondm);
23868be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
23878be3dfe1Sksagiyam $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
23888be3dfe1Sksagiyam $       DMGetGlobalVector(sectiondm, &vec);
23898be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
23908be3dfe1Sksagiyam $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
23918be3dfe1Sksagiyam $       DMRestoreGlobalVector(sectiondm, &vec);
23928be3dfe1Sksagiyam $       PetscSFDestroy(&gsf);
23938be3dfe1Sksagiyam $       PetscSFDestroy(&sfX);
23948be3dfe1Sksagiyam $       DMDestroy(&sectiondm);
23958be3dfe1Sksagiyam $       DMDestroy(&dm);
23968be3dfe1Sksagiyam 
2397db781477SPatrick Sanan .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`
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));
24328be3dfe1Sksagiyam   PetscFunctionReturn(0);
24338be3dfe1Sksagiyam }
24348be3dfe1Sksagiyam 
24358be3dfe1Sksagiyam /*@
24368be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
24378be3dfe1Sksagiyam 
24388be3dfe1Sksagiyam   Collective on DM
24398be3dfe1Sksagiyam 
24408be3dfe1Sksagiyam   Input Parameters:
24418be3dfe1Sksagiyam + dm        - The DM that represents the topology
24428be3dfe1Sksagiyam . viewer    - The PetscViewer that represents the on-disk vector data
24438be3dfe1Sksagiyam . sectiondm - The DM that contains the local section on which vec is defined
24448be3dfe1Sksagiyam . sf        - The SF 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:
24508be3dfe1Sksagiyam   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 
24528be3dfe1Sksagiyam   Typical calling sequence
24538be3dfe1Sksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
24548be3dfe1Sksagiyam $       DMSetType(dm, DMPLEX);
24558be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
24568be3dfe1Sksagiyam $       DMPlexTopologyLoad(dm, viewer, &sfX);
24578be3dfe1Sksagiyam $       DMClone(dm, &sectiondm);
24588be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
24598be3dfe1Sksagiyam $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
24608be3dfe1Sksagiyam $       DMGetLocalVector(sectiondm, &vec);
24618be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
24628be3dfe1Sksagiyam $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
24638be3dfe1Sksagiyam $       DMRestoreLocalVector(sectiondm, &vec);
24648be3dfe1Sksagiyam $       PetscSFDestroy(&lsf);
24658be3dfe1Sksagiyam $       PetscSFDestroy(&sfX);
24668be3dfe1Sksagiyam $       DMDestroy(&sectiondm);
24678be3dfe1Sksagiyam $       DMDestroy(&dm);
24688be3dfe1Sksagiyam 
2469db781477SPatrick Sanan .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`
24708be3dfe1Sksagiyam @*/
2471d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2472d71ae5a4SJacob Faibussowitsch {
24738be3dfe1Sksagiyam   PetscBool ishdf5;
24748be3dfe1Sksagiyam 
24758be3dfe1Sksagiyam   PetscFunctionBegin;
24768be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24778be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24788be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24798be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
24808be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
24818be3dfe1Sksagiyam   /* Check consistency */
24828be3dfe1Sksagiyam   {
24838be3dfe1Sksagiyam     PetscSection section;
24848be3dfe1Sksagiyam     PetscBool    includesConstraints;
24858be3dfe1Sksagiyam     PetscInt     m, m1;
24868be3dfe1Sksagiyam 
24879566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24889566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
24899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24909566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24919566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
249263a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
24938be3dfe1Sksagiyam   }
24949566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
24968be3dfe1Sksagiyam   if (ishdf5) {
24978be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
24989566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
24998be3dfe1Sksagiyam #else
25008be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
25018be3dfe1Sksagiyam #endif
25028be3dfe1Sksagiyam   }
25039566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
25048be3dfe1Sksagiyam   PetscFunctionReturn(0);
25058be3dfe1Sksagiyam }
25068be3dfe1Sksagiyam 
2507d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2508d71ae5a4SJacob Faibussowitsch {
2509552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2510552f7358SJed Brown 
2511552f7358SJed Brown   PetscFunctionBegin;
25129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
25139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
25149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
25159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
25162e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL));
25172e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
25182e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
25192e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
25202e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
25216bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
25226bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2523c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2524c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
25250d644c17SKarl Rupp   if (--mesh->refct > 0) PetscFunctionReturn(0);
25269566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
25279566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
25289566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
25299566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
25309566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
25319566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
2532*9f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
25339566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->facesTmp));
25349566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
25359566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
25369566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
25371d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
25389566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
25399566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
25409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
25419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
25429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
25439566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
25449566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
25459566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
25469566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
25479566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
25489566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
25499566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
25509566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
25519566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
25529566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
25539566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2554552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
25559566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
2556552f7358SJed Brown   PetscFunctionReturn(0);
2557552f7358SJed Brown }
2558552f7358SJed Brown 
2559d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2560d71ae5a4SJacob Faibussowitsch {
25618d1174e4SMatthew G. Knepley   PetscSection           sectionGlobal;
2562acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
25639fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2564837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2565b412c318SBarry Smith   MatType                mtype;
25661428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2567552f7358SJed Brown 
2568552f7358SJed Brown   PetscFunctionBegin;
25699566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2570b412c318SBarry Smith   mtype = dm->mattype;
25719566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
25729566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
25739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
25749fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
25759566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
25769566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
25779566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
25789566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
25799566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2580acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
25819566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
25829566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
25839566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
25849566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
25859566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
25869566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
25879566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
25889566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2589552f7358SJed Brown   if (!isShell) {
2590837628f4SStefano Zampini     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
25919fca9976SJed Brown     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2592fad22124SMatthew G Knepley     PetscInt  pStart, pEnd, p, dof, cdof;
2593552f7358SJed Brown 
25949566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
25959fca9976SJed Brown 
25969fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
25979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2598e432b41dSStefano Zampini     for (p = pStart; p < pEnd; ++p) {
25999fca9976SJed Brown       PetscInt bdof, offset;
2600a9d99c84SMatthew G. Knepley 
26019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
26029fca9976SJed Brown       PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
26039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
26049371c9d4SSatish Balay       for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof;
26051d17a0a3SMatthew G. Knepley       dof  = dof < 0 ? -(dof + 1) : dof;
26061d17a0a3SMatthew G. Knepley       bdof = cdof && (dof - cdof) ? 1 : dof;
26071d17a0a3SMatthew G. Knepley       if (dof) {
26089371c9d4SSatish Balay         if (bs < 0) {
26099371c9d4SSatish Balay           bs = bdof;
26109371c9d4SSatish Balay         } else if (bs != bdof) {
26119371c9d4SSatish Balay           bs = 1;
26129371c9d4SSatish Balay         }
2613552f7358SJed Brown       }
26142a28c762SMatthew G Knepley     }
26152a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2616e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2617e432b41dSStefano Zampini     bsLocal[1] = bs;
26189566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2619e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2620e432b41dSStefano Zampini     else bs = bsMinMax[0];
26216fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
26229566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
26230682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
26249566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
26259566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
26260682b8bbSJed Brown     } else {
26279566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
26289566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
26299566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2630552f7358SJed Brown     }
26319fca9976SJed Brown     { // Consolidate blocks
26329fca9976SJed Brown       PetscInt nblocks = 0;
26339fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
26349fca9976SJed Brown         if (pblocks[i] == 0) continue;
26359fca9976SJed Brown         pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2636ad540459SPierre 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]);
26379fca9976SJed Brown       }
26389fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
26399fca9976SJed Brown     }
26409fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2641aa0f6e3cSJed Brown   }
26429566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
2643552f7358SJed Brown   PetscFunctionReturn(0);
2644552f7358SJed Brown }
2645552f7358SJed Brown 
26467cd05799SMatthew G. Knepley /*@
2647a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2648be36d101SStefano Zampini 
2649be36d101SStefano Zampini   Not collective
2650be36d101SStefano Zampini 
2651be36d101SStefano Zampini   Input Parameter:
2652be36d101SStefano Zampini . mesh - The DMPlex
2653be36d101SStefano Zampini 
2654be36d101SStefano Zampini   Output Parameters:
2655be36d101SStefano Zampini . subsection - The subdomain section
2656be36d101SStefano Zampini 
2657be36d101SStefano Zampini   Level: developer
2658be36d101SStefano Zampini 
2659be36d101SStefano Zampini .seealso:
26607cd05799SMatthew G. Knepley @*/
2661d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2662d71ae5a4SJacob Faibussowitsch {
2663be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
2664be36d101SStefano Zampini 
2665be36d101SStefano Zampini   PetscFunctionBegin;
2666be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2667be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2668be36d101SStefano Zampini     PetscSection section;
2669be36d101SStefano Zampini     PetscSF      sf;
2670be36d101SStefano Zampini 
26719566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
26729566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
26739566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
26749566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2675be36d101SStefano Zampini   }
2676be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
2677be36d101SStefano Zampini   PetscFunctionReturn(0);
2678be36d101SStefano Zampini }
2679be36d101SStefano Zampini 
2680552f7358SJed Brown /*@
2681552f7358SJed Brown   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2682552f7358SJed Brown 
2683552f7358SJed Brown   Not collective
2684552f7358SJed Brown 
2685552f7358SJed Brown   Input Parameter:
2686552f7358SJed Brown . mesh - The DMPlex
2687552f7358SJed Brown 
2688552f7358SJed Brown   Output Parameters:
2689552f7358SJed Brown + pStart - The first mesh point
2690552f7358SJed Brown - pEnd   - The upper bound for mesh points
2691552f7358SJed Brown 
2692552f7358SJed Brown   Level: beginner
2693552f7358SJed Brown 
2694db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetChart()`
2695552f7358SJed Brown @*/
2696d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2697d71ae5a4SJacob Faibussowitsch {
2698552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2699552f7358SJed Brown 
2700552f7358SJed Brown   PetscFunctionBegin;
2701552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2702*9f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
2703*9f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2704552f7358SJed Brown   PetscFunctionReturn(0);
2705552f7358SJed Brown }
2706552f7358SJed Brown 
2707552f7358SJed Brown /*@
2708552f7358SJed Brown   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2709552f7358SJed Brown 
2710552f7358SJed Brown   Not collective
2711552f7358SJed Brown 
2712552f7358SJed Brown   Input Parameters:
2713552f7358SJed Brown + mesh - The DMPlex
2714552f7358SJed Brown . pStart - The first mesh point
2715552f7358SJed Brown - pEnd   - The upper bound for mesh points
2716552f7358SJed Brown 
2717552f7358SJed Brown   Output Parameters:
2718552f7358SJed Brown 
2719552f7358SJed Brown   Level: beginner
2720552f7358SJed Brown 
2721db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetChart()`
2722552f7358SJed Brown @*/
2723d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2724d71ae5a4SJacob Faibussowitsch {
2725552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2726552f7358SJed Brown 
2727552f7358SJed Brown   PetscFunctionBegin;
2728552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
27309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2731552f7358SJed Brown   PetscFunctionReturn(0);
2732552f7358SJed Brown }
2733552f7358SJed Brown 
2734552f7358SJed Brown /*@
2735eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2736552f7358SJed Brown 
2737552f7358SJed Brown   Not collective
2738552f7358SJed Brown 
2739552f7358SJed Brown   Input Parameters:
2740552f7358SJed Brown + mesh - The DMPlex
2741eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
2742552f7358SJed Brown 
2743552f7358SJed Brown   Output Parameter:
2744552f7358SJed Brown . size - The cone size for point p
2745552f7358SJed Brown 
2746552f7358SJed Brown   Level: beginner
2747552f7358SJed Brown 
2748db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2749552f7358SJed Brown @*/
2750d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2751d71ae5a4SJacob Faibussowitsch {
2752552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2753552f7358SJed Brown 
2754552f7358SJed Brown   PetscFunctionBegin;
2755552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2756dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
2757*9f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
2758*9f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
2759552f7358SJed Brown   PetscFunctionReturn(0);
2760552f7358SJed Brown }
2761552f7358SJed Brown 
2762552f7358SJed Brown /*@
2763eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2764552f7358SJed Brown 
2765552f7358SJed Brown   Not collective
2766552f7358SJed Brown 
2767552f7358SJed Brown   Input Parameters:
2768552f7358SJed Brown + mesh - The DMPlex
2769eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2770552f7358SJed Brown - size - The cone size for point p
2771552f7358SJed Brown 
2772552f7358SJed Brown   Output Parameter:
2773552f7358SJed Brown 
2774552f7358SJed Brown   Note:
2775552f7358SJed Brown   This should be called after DMPlexSetChart().
2776552f7358SJed Brown 
2777552f7358SJed Brown   Level: beginner
2778552f7358SJed Brown 
2779db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2780552f7358SJed Brown @*/
2781d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2782d71ae5a4SJacob Faibussowitsch {
2783552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2784552f7358SJed Brown 
2785552f7358SJed Brown   PetscFunctionBegin;
2786552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2787*9f4ada15SMatthew G. Knepley   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
27889566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
2789552f7358SJed Brown   PetscFunctionReturn(0);
2790552f7358SJed Brown }
2791552f7358SJed Brown 
2792552f7358SJed Brown /*@C
2793eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2794552f7358SJed Brown 
2795552f7358SJed Brown   Not collective
2796552f7358SJed Brown 
2797552f7358SJed Brown   Input Parameters:
2798833c876bSVaclav Hapla + dm - The DMPlex
2799eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
2800552f7358SJed Brown 
2801552f7358SJed Brown   Output Parameter:
2802552f7358SJed Brown . cone - An array of points which are on the in-edges for point p
2803552f7358SJed Brown 
2804552f7358SJed Brown   Level: beginner
2805552f7358SJed Brown 
28063813dfbdSMatthew G Knepley   Fortran Notes:
28073813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
28083813dfbdSMatthew G Knepley   include petsc.h90 in your code.
2809922102d1SVaclav Hapla   You must also call DMPlexRestoreCone() after you finish using the returned array.
2810922102d1SVaclav Hapla   DMPlexRestoreCone() is not needed/available in C.
28113813dfbdSMatthew G Knepley 
2812db781477SPatrick Sanan .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`
2813552f7358SJed Brown @*/
2814d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2815d71ae5a4SJacob Faibussowitsch {
2816552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2817552f7358SJed Brown   PetscInt off;
2818552f7358SJed Brown 
2819552f7358SJed Brown   PetscFunctionBegin;
2820552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2821552f7358SJed Brown   PetscValidPointer(cone, 3);
28229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
2823552f7358SJed Brown   *cone = &mesh->cones[off];
2824552f7358SJed Brown   PetscFunctionReturn(0);
2825552f7358SJed Brown }
2826552f7358SJed Brown 
28270ce7577fSVaclav Hapla /*@C
28280ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
28290ce7577fSVaclav Hapla 
28300ce7577fSVaclav Hapla   Not collective
28310ce7577fSVaclav Hapla 
28320ce7577fSVaclav Hapla   Input Parameters:
28330ce7577fSVaclav Hapla + dm - The DMPlex
28340ce7577fSVaclav Hapla - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
28350ce7577fSVaclav Hapla 
2836d8d19677SJose E. Roman   Output Parameters:
28370ce7577fSVaclav Hapla + pConesSection - PetscSection describing the layout of pCones
28380ce7577fSVaclav Hapla - pCones - An array of points which are on the in-edges for the point set p
28390ce7577fSVaclav Hapla 
28400ce7577fSVaclav Hapla   Level: intermediate
28410ce7577fSVaclav Hapla 
2842db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`
28430ce7577fSVaclav Hapla @*/
2844d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2845d71ae5a4SJacob Faibussowitsch {
28460ce7577fSVaclav Hapla   PetscSection cs, newcs;
28470ce7577fSVaclav Hapla   PetscInt    *cones;
28480ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
28490ce7577fSVaclav Hapla   PetscInt     n;
28500ce7577fSVaclav Hapla 
28510ce7577fSVaclav Hapla   PetscFunctionBegin;
28529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
28539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
28549566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
28550ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
28560ce7577fSVaclav Hapla   if (pCones) {
28579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
28589566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
28590ce7577fSVaclav Hapla   }
28600ce7577fSVaclav Hapla   PetscFunctionReturn(0);
28610ce7577fSVaclav Hapla }
28620ce7577fSVaclav Hapla 
2863af9eab45SVaclav Hapla /*@
2864af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2865d4636a37SVaclav Hapla 
2866d4636a37SVaclav Hapla   Not collective
2867d4636a37SVaclav Hapla 
2868d4636a37SVaclav Hapla   Input Parameters:
2869d4636a37SVaclav Hapla + dm - The DMPlex
2870af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2871d4636a37SVaclav Hapla 
2872d4636a37SVaclav Hapla   Output Parameter:
2873af9eab45SVaclav Hapla . expandedPoints - An array of vertices recursively expanded from input points
2874d4636a37SVaclav Hapla 
2875d4636a37SVaclav Hapla   Level: advanced
2876d4636a37SVaclav Hapla 
2877af9eab45SVaclav Hapla   Notes:
2878af9eab45SVaclav Hapla   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2879af9eab45SVaclav Hapla   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2880af9eab45SVaclav Hapla 
2881db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()`
2882d4636a37SVaclav Hapla @*/
2883d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2884d71ae5a4SJacob Faibussowitsch {
2885af9eab45SVaclav Hapla   IS      *expandedPointsAll;
2886af9eab45SVaclav Hapla   PetscInt depth;
2887d4636a37SVaclav Hapla 
2888d4636a37SVaclav Hapla   PetscFunctionBegin;
2889af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2890af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2891af9eab45SVaclav Hapla   PetscValidPointer(expandedPoints, 3);
28929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2893af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
28949566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
28959566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2896af9eab45SVaclav Hapla   PetscFunctionReturn(0);
2897af9eab45SVaclav Hapla }
2898af9eab45SVaclav Hapla 
2899af9eab45SVaclav Hapla /*@
2900af9eab45SVaclav 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).
2901af9eab45SVaclav Hapla 
2902af9eab45SVaclav Hapla   Not collective
2903af9eab45SVaclav Hapla 
2904af9eab45SVaclav Hapla   Input Parameters:
2905af9eab45SVaclav Hapla + dm - The DMPlex
2906af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2907af9eab45SVaclav Hapla 
2908d8d19677SJose E. Roman   Output Parameters:
2909af9eab45SVaclav Hapla + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2910af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
2911af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
2912af9eab45SVaclav Hapla 
2913af9eab45SVaclav Hapla   Level: advanced
2914af9eab45SVaclav Hapla 
2915af9eab45SVaclav Hapla   Notes:
2916af9eab45SVaclav Hapla   Like DMPlexGetConeTuple() but recursive.
2917af9eab45SVaclav Hapla 
2918af9eab45SVaclav Hapla   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.
2919af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2920af9eab45SVaclav Hapla 
2921af9eab45SVaclav Hapla   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:
2922af9eab45SVaclav Hapla   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2923af9eab45SVaclav Hapla   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2924af9eab45SVaclav Hapla 
2925db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()`
2926af9eab45SVaclav Hapla @*/
2927d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2928d71ae5a4SJacob Faibussowitsch {
2929af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
2930af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
2931af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
2932af9eab45SVaclav Hapla   IS             *expandedPoints_;
2933af9eab45SVaclav Hapla   PetscSection   *sections_;
2934af9eab45SVaclav Hapla 
2935af9eab45SVaclav Hapla   PetscFunctionBegin;
2936af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2937af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2938af9eab45SVaclav Hapla   if (depth) PetscValidIntPointer(depth, 3);
2939af9eab45SVaclav Hapla   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2940af9eab45SVaclav Hapla   if (sections) PetscValidPointer(sections, 5);
29419566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
29429566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
29439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
29449566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
29459566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
2946af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
2947af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
29489566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
29499566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
2950af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
29519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
2952af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
29539566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
29549566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
2955af9eab45SVaclav Hapla       } else {
29569566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
2957af9eab45SVaclav Hapla       }
2958af9eab45SVaclav Hapla     }
29599566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
29609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
29619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
2962af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
29639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
29649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
2965af9eab45SVaclav Hapla       if (cn > 1) {
29669566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
29679566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
2968af9eab45SVaclav Hapla       } else {
2969af9eab45SVaclav Hapla         newarr[co] = arr[i];
2970af9eab45SVaclav Hapla       }
2971af9eab45SVaclav Hapla     }
29729566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
2973af9eab45SVaclav Hapla     arr = newarr;
2974af9eab45SVaclav Hapla     n   = newn;
2975af9eab45SVaclav Hapla   }
29769566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
2977af9eab45SVaclav Hapla   *depth = depth_;
2978af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
2979af9eab45SVaclav Hapla   else {
29809566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
29819566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
2982af9eab45SVaclav Hapla   }
2983af9eab45SVaclav Hapla   if (sections) *sections = sections_;
2984af9eab45SVaclav Hapla   else {
29859566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
29869566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
2987af9eab45SVaclav Hapla   }
2988af9eab45SVaclav Hapla   PetscFunctionReturn(0);
2989af9eab45SVaclav Hapla }
2990af9eab45SVaclav Hapla 
2991af9eab45SVaclav Hapla /*@
2992af9eab45SVaclav Hapla   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2993af9eab45SVaclav Hapla 
2994af9eab45SVaclav Hapla   Not collective
2995af9eab45SVaclav Hapla 
2996af9eab45SVaclav Hapla   Input Parameters:
2997af9eab45SVaclav Hapla + dm - The DMPlex
2998af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2999af9eab45SVaclav Hapla 
3000d8d19677SJose E. Roman   Output Parameters:
3001af9eab45SVaclav Hapla + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
3002af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3003af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
3004af9eab45SVaclav Hapla 
3005af9eab45SVaclav Hapla   Level: advanced
3006af9eab45SVaclav Hapla 
3007af9eab45SVaclav Hapla   Notes:
3008af9eab45SVaclav Hapla   See DMPlexGetConeRecursive() for details.
3009af9eab45SVaclav Hapla 
3010db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()`
3011af9eab45SVaclav Hapla @*/
3012d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3013d71ae5a4SJacob Faibussowitsch {
3014af9eab45SVaclav Hapla   PetscInt d, depth_;
3015af9eab45SVaclav Hapla 
3016af9eab45SVaclav Hapla   PetscFunctionBegin;
30179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
30181dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3019af9eab45SVaclav Hapla   if (depth) *depth = 0;
3020af9eab45SVaclav Hapla   if (expandedPoints) {
30219566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
30229566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3023af9eab45SVaclav Hapla   }
3024af9eab45SVaclav Hapla   if (sections) {
30259566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
30269566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3027af9eab45SVaclav Hapla   }
3028d4636a37SVaclav Hapla   PetscFunctionReturn(0);
3029d4636a37SVaclav Hapla }
3030d4636a37SVaclav Hapla 
3031552f7358SJed Brown /*@
303292371b87SBarry 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
3033552f7358SJed Brown 
3034552f7358SJed Brown   Not collective
3035552f7358SJed Brown 
3036552f7358SJed Brown   Input Parameters:
3037552f7358SJed Brown + mesh - The DMPlex
3038eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3039552f7358SJed Brown - cone - An array of points which are on the in-edges for point p
3040552f7358SJed Brown 
3041552f7358SJed Brown   Output Parameter:
3042552f7358SJed Brown 
3043552f7358SJed Brown   Note:
3044552f7358SJed Brown   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
3045552f7358SJed Brown 
3046552f7358SJed Brown   Level: beginner
3047552f7358SJed Brown 
3048db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3049552f7358SJed Brown @*/
3050d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3051d71ae5a4SJacob Faibussowitsch {
3052552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3053552f7358SJed Brown   PetscInt pStart, pEnd;
3054552f7358SJed Brown   PetscInt dof, off, c;
3055552f7358SJed Brown 
3056552f7358SJed Brown   PetscFunctionBegin;
3057552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
30599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3060dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(cone, 3);
30619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
306263a3b9bcSJacob 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);
3063552f7358SJed Brown   for (c = 0; c < dof; ++c) {
306463a3b9bcSJacob 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);
3065552f7358SJed Brown     mesh->cones[off + c] = cone[c];
3066552f7358SJed Brown   }
3067552f7358SJed Brown   PetscFunctionReturn(0);
3068552f7358SJed Brown }
3069552f7358SJed Brown 
3070552f7358SJed Brown /*@C
3071eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3072552f7358SJed Brown 
3073552f7358SJed Brown   Not collective
3074552f7358SJed Brown 
3075552f7358SJed Brown   Input Parameters:
3076552f7358SJed Brown + mesh - The DMPlex
3077eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3078552f7358SJed Brown 
3079552f7358SJed Brown   Output Parameter:
3080552f7358SJed Brown . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
3081b5a892a1SMatthew G. Knepley                     integer giving the prescription for cone traversal.
3082552f7358SJed Brown 
3083552f7358SJed Brown   Level: beginner
3084552f7358SJed Brown 
3085b5a892a1SMatthew G. Knepley   Notes:
3086b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3087b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3088b5a892a1SMatthew G. Knepley   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
3089b5a892a1SMatthew G. Knepley   with the identity.
3090b5a892a1SMatthew G. Knepley 
30913813dfbdSMatthew G Knepley   Fortran Notes:
30923813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
30933813dfbdSMatthew G Knepley   include petsc.h90 in your code.
30943b12b3d8SVaclav Hapla   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
3095922102d1SVaclav Hapla   DMPlexRestoreConeOrientation() is not needed/available in C.
30963813dfbdSMatthew G Knepley 
3097db781477SPatrick Sanan .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3098552f7358SJed Brown @*/
3099d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3100d71ae5a4SJacob Faibussowitsch {
3101552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3102552f7358SJed Brown   PetscInt off;
3103552f7358SJed Brown 
3104552f7358SJed Brown   PetscFunctionBegin;
3105552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
310676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3107552f7358SJed Brown     PetscInt dof;
31089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3109552f7358SJed Brown     if (dof) PetscValidPointer(coneOrientation, 3);
3110552f7358SJed Brown   }
31119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
31120d644c17SKarl Rupp 
3113552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
3114552f7358SJed Brown   PetscFunctionReturn(0);
3115552f7358SJed Brown }
3116552f7358SJed Brown 
3117552f7358SJed Brown /*@
3118eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3119552f7358SJed Brown 
3120552f7358SJed Brown   Not collective
3121552f7358SJed Brown 
3122552f7358SJed Brown   Input Parameters:
3123552f7358SJed Brown + mesh - The DMPlex
3124eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3125b5a892a1SMatthew G. Knepley - coneOrientation - An array of orientations
3126552f7358SJed Brown   Output Parameter:
3127552f7358SJed Brown 
3128b5a892a1SMatthew G. Knepley   Notes:
3129552f7358SJed Brown   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
3130552f7358SJed Brown 
3131b5a892a1SMatthew G. Knepley   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
3132b5a892a1SMatthew G. Knepley 
3133552f7358SJed Brown   Level: beginner
3134552f7358SJed Brown 
3135db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3136552f7358SJed Brown @*/
3137d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3138d71ae5a4SJacob Faibussowitsch {
3139552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3140552f7358SJed Brown   PetscInt pStart, pEnd;
3141552f7358SJed Brown   PetscInt dof, off, c;
3142552f7358SJed Brown 
3143552f7358SJed Brown   PetscFunctionBegin;
3144552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
31469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3147dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(coneOrientation, 3);
31489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
314963a3b9bcSJacob 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);
3150552f7358SJed Brown   for (c = 0; c < dof; ++c) {
3151552f7358SJed Brown     PetscInt cdof, o = coneOrientation[c];
3152552f7358SJed Brown 
31539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
31541dca8a05SBarry 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);
3155552f7358SJed Brown     mesh->coneOrientations[off + c] = o;
3156552f7358SJed Brown   }
3157552f7358SJed Brown   PetscFunctionReturn(0);
3158552f7358SJed Brown }
3159552f7358SJed Brown 
31607cd05799SMatthew G. Knepley /*@
3161eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
31627cd05799SMatthew G. Knepley 
31637cd05799SMatthew G. Knepley   Not collective
31647cd05799SMatthew G. Knepley 
31657cd05799SMatthew G. Knepley   Input Parameters:
31667cd05799SMatthew G. Knepley + mesh - The DMPlex
3167eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
31687cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
31697cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
31707cd05799SMatthew G. Knepley 
31717cd05799SMatthew G. Knepley   Level: beginner
31727cd05799SMatthew G. Knepley 
3173db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
31747cd05799SMatthew G. Knepley @*/
3175d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3176d71ae5a4SJacob Faibussowitsch {
3177552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3178552f7358SJed Brown   PetscInt pStart, pEnd;
3179552f7358SJed Brown   PetscInt dof, off;
3180552f7358SJed Brown 
3181552f7358SJed Brown   PetscFunctionBegin;
3182552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
318463a3b9bcSJacob 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);
318563a3b9bcSJacob 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);
31869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
31879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
318863a3b9bcSJacob 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);
3189552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
3190552f7358SJed Brown   PetscFunctionReturn(0);
3191552f7358SJed Brown }
3192552f7358SJed Brown 
31937cd05799SMatthew G. Knepley /*@
3194eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
31957cd05799SMatthew G. Knepley 
31967cd05799SMatthew G. Knepley   Not collective
31977cd05799SMatthew G. Knepley 
31987cd05799SMatthew G. Knepley   Input Parameters:
31997cd05799SMatthew G. Knepley + mesh - The DMPlex
3200eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
32017cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
32027cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
32037cd05799SMatthew G. Knepley 
32047cd05799SMatthew G. Knepley   Level: beginner
32057cd05799SMatthew G. Knepley 
3206b5a892a1SMatthew G. Knepley   Notes:
3207b5a892a1SMatthew G. Knepley   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3208b5a892a1SMatthew G. Knepley 
3209db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
32107cd05799SMatthew G. Knepley @*/
3211d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3212d71ae5a4SJacob Faibussowitsch {
321377c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
321477c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
321577c88f5bSMatthew G Knepley   PetscInt dof, off;
321677c88f5bSMatthew G Knepley 
321777c88f5bSMatthew G Knepley   PetscFunctionBegin;
321877c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
322063a3b9bcSJacob 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);
32219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
32229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
322363a3b9bcSJacob 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);
322477c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
322577c88f5bSMatthew G Knepley   PetscFunctionReturn(0);
322677c88f5bSMatthew G Knepley }
322777c88f5bSMatthew G Knepley 
3228*9f4ada15SMatthew G. Knepley /*@C
3229*9f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
3230*9f4ada15SMatthew G. Knepley 
3231*9f4ada15SMatthew G. Knepley   Not collective
3232*9f4ada15SMatthew G. Knepley 
3233*9f4ada15SMatthew G. Knepley   Input Parameters:
3234*9f4ada15SMatthew G. Knepley + dm - The DMPlex
3235*9f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
3236*9f4ada15SMatthew G. Knepley 
3237*9f4ada15SMatthew G. Knepley   Output Parameters:
3238*9f4ada15SMatthew G. Knepley + cone - An array of points which are on the in-edges for point p
3239*9f4ada15SMatthew G. Knepley - ornt - An array of orientations which are on the in-edges for point p. An orientation is an
3240*9f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
3241*9f4ada15SMatthew G. Knepley 
3242*9f4ada15SMatthew G. Knepley   Level: beginner
3243*9f4ada15SMatthew G. Knepley 
3244*9f4ada15SMatthew G. Knepley   Notes:
3245*9f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3246*9f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3247*9f4ada15SMatthew G. Knepley   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
3248*9f4ada15SMatthew G. Knepley   with the identity.
3249*9f4ada15SMatthew G. Knepley 
3250*9f4ada15SMatthew G. Knepley   Fortran Notes:
3251*9f4ada15SMatthew G. Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
3252*9f4ada15SMatthew G. Knepley   include petsc.h90 in your code.
3253*9f4ada15SMatthew G. Knepley   You must also call DMPlexRestoreCone() after you finish using the returned array.
3254*9f4ada15SMatthew G. Knepley   DMPlexRestoreCone() is not needed/available in C.
3255*9f4ada15SMatthew G. Knepley 
3256*9f4ada15SMatthew G. Knepley .seealso: `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3257*9f4ada15SMatthew G. Knepley @*/
3258*9f4ada15SMatthew G. Knepley PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3259*9f4ada15SMatthew G. Knepley {
3260*9f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
3261*9f4ada15SMatthew G. Knepley 
3262*9f4ada15SMatthew G. Knepley   PetscFunctionBegin;
3263*9f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3264*9f4ada15SMatthew G. Knepley   if (mesh->tr) {
3265*9f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
3266*9f4ada15SMatthew G. Knepley   } else {
3267*9f4ada15SMatthew G. Knepley     PetscInt off;
3268*9f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
3269*9f4ada15SMatthew G. Knepley       PetscInt dof;
3270*9f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3271*9f4ada15SMatthew G. Knepley       if (dof) {
3272*9f4ada15SMatthew G. Knepley         if (cone) PetscValidPointer(cone, 3);
3273*9f4ada15SMatthew G. Knepley         if (ornt) PetscValidPointer(ornt, 4);
3274*9f4ada15SMatthew G. Knepley       }
3275*9f4ada15SMatthew G. Knepley     }
3276*9f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3277*9f4ada15SMatthew G. Knepley     if (cone) *cone = &mesh->cones[off];
3278*9f4ada15SMatthew G. Knepley     if (ornt) *ornt = &mesh->coneOrientations[off];
3279*9f4ada15SMatthew G. Knepley   }
3280*9f4ada15SMatthew G. Knepley   PetscFunctionReturn(0);
3281*9f4ada15SMatthew G. Knepley }
3282*9f4ada15SMatthew G. Knepley 
3283*9f4ada15SMatthew G. Knepley /*@C
3284*9f4ada15SMatthew G. Knepley   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG
3285*9f4ada15SMatthew G. Knepley 
3286*9f4ada15SMatthew G. Knepley   Not collective
3287*9f4ada15SMatthew G. Knepley 
3288*9f4ada15SMatthew G. Knepley   Input Parameters:
3289*9f4ada15SMatthew G. Knepley + dm - The DMPlex
3290*9f4ada15SMatthew G. Knepley . p  - The point, which must lie in the chart set with DMPlexSetChart()
3291*9f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
3292*9f4ada15SMatthew G. Knepley - ornt - An array of orientations which are on the in-edges for point p. An orientation is an
3293*9f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
3294*9f4ada15SMatthew G. Knepley 
3295*9f4ada15SMatthew G. Knepley   Level: beginner
3296*9f4ada15SMatthew G. Knepley 
3297*9f4ada15SMatthew G. Knepley   Notes:
3298*9f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3299*9f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3300*9f4ada15SMatthew G. Knepley   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
3301*9f4ada15SMatthew G. Knepley   with the identity.
3302*9f4ada15SMatthew G. Knepley 
3303*9f4ada15SMatthew G. Knepley   Fortran Notes:
3304*9f4ada15SMatthew G. Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
3305*9f4ada15SMatthew G. Knepley   include petsc.h90 in your code.
3306*9f4ada15SMatthew G. Knepley   You must also call DMPlexRestoreCone() after you finish using the returned array.
3307*9f4ada15SMatthew G. Knepley   DMPlexRestoreCone() is not needed/available in C.
3308*9f4ada15SMatthew G. Knepley 
3309*9f4ada15SMatthew G. Knepley .seealso: `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3310*9f4ada15SMatthew G. Knepley @*/
3311*9f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3312*9f4ada15SMatthew G. Knepley {
3313*9f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
3314*9f4ada15SMatthew G. Knepley 
3315*9f4ada15SMatthew G. Knepley   PetscFunctionBegin;
3316*9f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3317*9f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
3318*9f4ada15SMatthew G. Knepley   PetscFunctionReturn(0);
3319*9f4ada15SMatthew G. Knepley }
3320*9f4ada15SMatthew G. Knepley 
3321552f7358SJed Brown /*@
3322eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3323552f7358SJed Brown 
3324552f7358SJed Brown   Not collective
3325552f7358SJed Brown 
3326552f7358SJed Brown   Input Parameters:
3327552f7358SJed Brown + mesh - The DMPlex
3328eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3329552f7358SJed Brown 
3330552f7358SJed Brown   Output Parameter:
3331552f7358SJed Brown . size - The support size for point p
3332552f7358SJed Brown 
3333552f7358SJed Brown   Level: beginner
3334552f7358SJed Brown 
3335db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3336552f7358SJed Brown @*/
3337d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3338d71ae5a4SJacob Faibussowitsch {
3339552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3340552f7358SJed Brown 
3341552f7358SJed Brown   PetscFunctionBegin;
3342552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3343dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
33449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3345552f7358SJed Brown   PetscFunctionReturn(0);
3346552f7358SJed Brown }
3347552f7358SJed Brown 
3348552f7358SJed Brown /*@
3349eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3350552f7358SJed Brown 
3351552f7358SJed Brown   Not collective
3352552f7358SJed Brown 
3353552f7358SJed Brown   Input Parameters:
3354552f7358SJed Brown + mesh - The DMPlex
3355eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3356552f7358SJed Brown - size - The support size for point p
3357552f7358SJed Brown 
3358552f7358SJed Brown   Output Parameter:
3359552f7358SJed Brown 
3360552f7358SJed Brown   Note:
3361552f7358SJed Brown   This should be called after DMPlexSetChart().
3362552f7358SJed Brown 
3363552f7358SJed Brown   Level: beginner
3364552f7358SJed Brown 
3365db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3366552f7358SJed Brown @*/
3367d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3368d71ae5a4SJacob Faibussowitsch {
3369552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3370552f7358SJed Brown 
3371552f7358SJed Brown   PetscFunctionBegin;
3372552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33739566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3374552f7358SJed Brown   PetscFunctionReturn(0);
3375552f7358SJed Brown }
3376552f7358SJed Brown 
3377552f7358SJed Brown /*@C
3378eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3379552f7358SJed Brown 
3380552f7358SJed Brown   Not collective
3381552f7358SJed Brown 
3382552f7358SJed Brown   Input Parameters:
3383552f7358SJed Brown + mesh - The DMPlex
3384eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3385552f7358SJed Brown 
3386552f7358SJed Brown   Output Parameter:
3387552f7358SJed Brown . support - An array of points which are on the out-edges for point p
3388552f7358SJed Brown 
3389552f7358SJed Brown   Level: beginner
3390552f7358SJed Brown 
33913813dfbdSMatthew G Knepley   Fortran Notes:
33923813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
33933813dfbdSMatthew G Knepley   include petsc.h90 in your code.
33943b12b3d8SVaclav Hapla   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3395922102d1SVaclav Hapla   DMPlexRestoreSupport() is not needed/available in C.
33963813dfbdSMatthew G Knepley 
3397db781477SPatrick Sanan .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3398552f7358SJed Brown @*/
3399d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3400d71ae5a4SJacob Faibussowitsch {
3401552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3402552f7358SJed Brown   PetscInt off;
3403552f7358SJed Brown 
3404552f7358SJed Brown   PetscFunctionBegin;
3405552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3406552f7358SJed Brown   PetscValidPointer(support, 3);
34079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3408552f7358SJed Brown   *support = &mesh->supports[off];
3409552f7358SJed Brown   PetscFunctionReturn(0);
3410552f7358SJed Brown }
3411552f7358SJed Brown 
3412552f7358SJed Brown /*@
341392371b87SBarry 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
3414552f7358SJed Brown 
3415552f7358SJed Brown   Not collective
3416552f7358SJed Brown 
3417552f7358SJed Brown   Input Parameters:
3418552f7358SJed Brown + mesh - The DMPlex
3419eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
342092371b87SBarry Smith - support - An array of points which are on the out-edges for point p
3421552f7358SJed Brown 
3422552f7358SJed Brown   Output Parameter:
3423552f7358SJed Brown 
3424552f7358SJed Brown   Note:
3425552f7358SJed Brown   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3426552f7358SJed Brown 
3427552f7358SJed Brown   Level: beginner
3428552f7358SJed Brown 
3429db781477SPatrick Sanan .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3430552f7358SJed Brown @*/
3431d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3432d71ae5a4SJacob Faibussowitsch {
3433552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3434552f7358SJed Brown   PetscInt pStart, pEnd;
3435552f7358SJed Brown   PetscInt dof, off, c;
3436552f7358SJed Brown 
3437552f7358SJed Brown   PetscFunctionBegin;
3438552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
34409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3441dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(support, 3);
34429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
344363a3b9bcSJacob 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);
3444552f7358SJed Brown   for (c = 0; c < dof; ++c) {
344563a3b9bcSJacob 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);
3446552f7358SJed Brown     mesh->supports[off + c] = support[c];
3447552f7358SJed Brown   }
3448552f7358SJed Brown   PetscFunctionReturn(0);
3449552f7358SJed Brown }
3450552f7358SJed Brown 
34517cd05799SMatthew G. Knepley /*@
3452eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
34537cd05799SMatthew G. Knepley 
34547cd05799SMatthew G. Knepley   Not collective
34557cd05799SMatthew G. Knepley 
34567cd05799SMatthew G. Knepley   Input Parameters:
34577cd05799SMatthew G. Knepley + mesh - The DMPlex
3458eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
34597cd05799SMatthew G. Knepley . supportPos - The local index in the cone where the point should be put
34607cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
34617cd05799SMatthew G. Knepley 
34627cd05799SMatthew G. Knepley   Level: beginner
34637cd05799SMatthew G. Knepley 
3464db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
34657cd05799SMatthew G. Knepley @*/
3466d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3467d71ae5a4SJacob Faibussowitsch {
3468552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3469552f7358SJed Brown   PetscInt pStart, pEnd;
3470552f7358SJed Brown   PetscInt dof, off;
3471552f7358SJed Brown 
3472552f7358SJed Brown   PetscFunctionBegin;
3473552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
34759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
34769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
347763a3b9bcSJacob 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);
347863a3b9bcSJacob 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);
347963a3b9bcSJacob 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);
3480552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
3481552f7358SJed Brown   PetscFunctionReturn(0);
3482552f7358SJed Brown }
3483552f7358SJed Brown 
3484b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3485d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3486d71ae5a4SJacob Faibussowitsch {
3487b5a892a1SMatthew G. Knepley   switch (ct) {
3488b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3489b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3490b5a892a1SMatthew G. Knepley     break;
3491b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3492b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3493b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3494b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3495b5a892a1SMatthew G. Knepley     break;
3496b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3497b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3498b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3499b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3500b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3501b5a892a1SMatthew G. Knepley     break;
3502d71ae5a4SJacob Faibussowitsch   default:
3503d71ae5a4SJacob Faibussowitsch     return o;
3504b5a892a1SMatthew G. Knepley   }
3505b5a892a1SMatthew G. Knepley   return o;
3506b5a892a1SMatthew G. Knepley }
3507b5a892a1SMatthew G. Knepley 
3508b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3509d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3510d71ae5a4SJacob Faibussowitsch {
3511b5a892a1SMatthew G. Knepley   switch (ct) {
3512b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3513b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3514b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3515b5a892a1SMatthew G. Knepley     break;
3516b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3517b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3518b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3519b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3520b5a892a1SMatthew G. Knepley     break;
3521b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3522b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3523b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3524b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3525b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3526b5a892a1SMatthew G. Knepley     break;
3527d71ae5a4SJacob Faibussowitsch   default:
3528d71ae5a4SJacob Faibussowitsch     return o;
3529b5a892a1SMatthew G. Knepley   }
3530b5a892a1SMatthew G. Knepley   return o;
3531b5a892a1SMatthew G. Knepley }
3532b5a892a1SMatthew G. Knepley 
3533b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3534d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3535d71ae5a4SJacob Faibussowitsch {
3536b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3537b5a892a1SMatthew G. Knepley 
3538b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
35399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3540b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3541b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3542b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3543b5a892a1SMatthew G. Knepley 
35449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
35459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
35469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3547b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3548b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3549b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3550b5a892a1SMatthew G. Knepley 
35519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3552b5a892a1SMatthew G. Knepley       switch (ct) {
3553b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
35549566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
35559566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3556b5a892a1SMatthew G. Knepley         break;
3557b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
35589566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
35599566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
35609566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3561b5a892a1SMatthew G. Knepley         break;
3562b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
35639566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
35649566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
35659566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
35669566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3567b5a892a1SMatthew G. Knepley         break;
3568d71ae5a4SJacob Faibussowitsch       default:
3569d71ae5a4SJacob Faibussowitsch         break;
3570b5a892a1SMatthew G. Knepley       }
3571b5a892a1SMatthew G. Knepley     }
3572b5a892a1SMatthew G. Knepley   }
3573b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3574b5a892a1SMatthew G. Knepley }
3575b5a892a1SMatthew G. Knepley 
3576d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3577d71ae5a4SJacob Faibussowitsch {
3578b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3579b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3580b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3581b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3582b5a892a1SMatthew G. Knepley 
3583b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3584b5a892a1SMatthew G. Knepley   if (ornt) {
35859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3586b5a892a1SMatthew G. Knepley     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3587b5a892a1SMatthew G. Knepley   }
3588b5a892a1SMatthew G. Knepley   if (*points) {
3589b5a892a1SMatthew G. Knepley     closure = *points;
3590b5a892a1SMatthew G. Knepley   } else {
3591b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
35929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
35939566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3594b5a892a1SMatthew G. Knepley   }
3595b5a892a1SMatthew G. Knepley   if (useCone) {
35969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &tmpSize));
35979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &tmp));
35989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO));
3599b5a892a1SMatthew G. Knepley   } else {
36009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize));
36019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &tmp));
3602b5a892a1SMatthew G. Knepley   }
3603b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3604b5a892a1SMatthew G. Knepley     closure[off++] = p;
3605b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3606b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3607b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3608b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3609b5a892a1SMatthew G. Knepley     }
3610b5a892a1SMatthew G. Knepley   } else {
36115f80ce2aSJacob Faibussowitsch     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3612b5a892a1SMatthew G. Knepley 
3613b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3614b5a892a1SMatthew G. Knepley     closure[off++] = p;
3615b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3616b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3617b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3618b5a892a1SMatthew G. Knepley 
36199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3620b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3621b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3622b5a892a1SMatthew G. Knepley     }
3623b5a892a1SMatthew G. Knepley   }
3624b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
3625b5a892a1SMatthew G. Knepley   if (points) *points = closure;
3626b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3627b5a892a1SMatthew G. Knepley }
3628b5a892a1SMatthew G. Knepley 
3629b5a892a1SMatthew G. Knepley /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3630d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3631d71ae5a4SJacob Faibussowitsch {
3632b5a892a1SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3633b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3634b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
3635b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3636b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3637b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3638b5a892a1SMatthew G. Knepley 
3639b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
36409566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
36419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
36429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
36439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &ornt));
36449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3645b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3646b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3647b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
36489371c9d4SSatish Balay   if (*points) {
36499371c9d4SSatish Balay     pts = *points;
36509371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3651b5a892a1SMatthew G. Knepley   c        = 0;
3652b5a892a1SMatthew G. Knepley   pts[c++] = point;
3653b5a892a1SMatthew G. Knepley   pts[c++] = o;
36549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
36559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
36569371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
36579371c9d4SSatish Balay     pts[c++] = closure[cl];
36589371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
36599371c9d4SSatish Balay   }
36609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
36619371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
36629371c9d4SSatish Balay     pts[c++] = closure[cl];
36639371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
36649371c9d4SSatish Balay   }
36659566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3666b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
36679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3668b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
3669b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3670b5a892a1SMatthew G. Knepley   }
3671b5a892a1SMatthew G. Knepley   if (dim >= 3) {
3672b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
3673b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3674b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
3675b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
3676b5a892a1SMatthew G. Knepley 
36779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3678b5a892a1SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
36799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize));
36809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, fpoint, &fcone));
36819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt));
3682b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
3683b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3684b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
3685b5a892a1SMatthew G. Knepley 
36869371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
36879371c9d4SSatish Balay           if (pts[i] == cp) break;
3688b5a892a1SMatthew G. Knepley         if (i == c) {
36899566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3690b5a892a1SMatthew G. Knepley           pts[c++] = cp;
3691b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3692b5a892a1SMatthew G. Knepley         }
3693b5a892a1SMatthew G. Knepley       }
3694b5a892a1SMatthew G. Knepley     }
3695b5a892a1SMatthew G. Knepley   }
3696b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
3697b5a892a1SMatthew G. Knepley   *points    = pts;
3698b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3699b5a892a1SMatthew G. Knepley }
3700b5a892a1SMatthew G. Knepley 
3701d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3702d71ae5a4SJacob Faibussowitsch {
3703b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
3704b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
3705b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3706b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3707b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
3708b5a892a1SMatthew G. Knepley 
3709b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
37109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
3711b5a892a1SMatthew G. Knepley   if (depth == 1) {
37129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3713b5a892a1SMatthew G. Knepley     PetscFunctionReturn(0);
3714b5a892a1SMatthew G. Knepley   }
37159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
3716b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3717b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
37189566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3719b5a892a1SMatthew G. Knepley     PetscFunctionReturn(0);
3720b5a892a1SMatthew G. Knepley   }
37219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3722b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3723b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3724b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
37259566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
37269371c9d4SSatish Balay   if (*points) {
37279371c9d4SSatish Balay     closure = *points;
37289371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
3729b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
3730b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
3731b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
3732b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
3733b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
3734b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3735b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
3736b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
3737b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
3738b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
3739b5a892a1SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3740b5a892a1SMatthew G. Knepley     const PetscInt      *tmp, *tmpO;
3741b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
3742b5a892a1SMatthew G. Knepley 
3743b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
3744b5a892a1SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2;
374563a3b9bcSJacob 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);
3746b5a892a1SMatthew G. Knepley     }
3747b5a892a1SMatthew G. Knepley     if (useCone) {
37489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &tmpSize));
37499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &tmp));
37509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO));
3751b5a892a1SMatthew G. Knepley     } else {
37529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize));
37539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, q, &tmp));
3754b5a892a1SMatthew G. Knepley       tmpO = NULL;
3755b5a892a1SMatthew G. Knepley     }
3756b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3757b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
3758b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
3759b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
37609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
3761b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3762b5a892a1SMatthew G. Knepley       PetscInt       c;
3763b5a892a1SMatthew G. Knepley 
3764b5a892a1SMatthew G. Knepley       /* Check for duplicate */
3765b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
3766b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
3767b5a892a1SMatthew G. Knepley       }
3768b5a892a1SMatthew G. Knepley       if (c == closureSize) {
3769b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
3770b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
3771b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
3772b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
3773b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
3774b5a892a1SMatthew G. Knepley       }
3775b5a892a1SMatthew G. Knepley     }
3776b5a892a1SMatthew G. Knepley   }
37779566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3778b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
3779b5a892a1SMatthew G. Knepley   if (points) *points = closure;
3780b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3781b5a892a1SMatthew G. Knepley }
3782b5a892a1SMatthew G. Knepley 
3783552f7358SJed Brown /*@C
3784eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3785552f7358SJed Brown 
3786552f7358SJed Brown   Not collective
3787552f7358SJed Brown 
3788552f7358SJed Brown   Input Parameters:
3789b5a892a1SMatthew G. Knepley + dm      - The DMPlex
3790b5a892a1SMatthew G. Knepley . p       - The mesh point
37916b867d5aSJose E. Roman - useCone - PETSC_TRUE for the closure, otherwise return the star
3792552f7358SJed Brown 
37936b867d5aSJose E. Roman   Input/Output Parameter:
37946b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
37956b867d5aSJose E. Roman            if NULL on input, internal storage will be returned, otherwise the provided array is used
37966b867d5aSJose E. Roman 
37976b867d5aSJose E. Roman   Output Parameter:
37986b867d5aSJose E. Roman . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3799552f7358SJed Brown 
3800552f7358SJed Brown   Note:
38010298fd71SBarry Smith   If using internal storage (points is NULL on input), each call overwrites the last output.
3802552f7358SJed Brown 
38039f22da38SBarry Smith   Fortran Note:
38043813dfbdSMatthew G Knepley   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
38053813dfbdSMatthew G Knepley 
3806552f7358SJed Brown   Level: beginner
3807552f7358SJed Brown 
3808db781477SPatrick Sanan .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3809552f7358SJed Brown @*/
3810d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3811d71ae5a4SJacob Faibussowitsch {
3812b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3813552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3814b5a892a1SMatthew G. Knepley   if (numPoints) PetscValidIntPointer(numPoints, 4);
3815b5a892a1SMatthew G. Knepley   if (points) PetscValidPointer(points, 5);
38169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
38179bf0dad6SMatthew G. Knepley   PetscFunctionReturn(0);
38189bf0dad6SMatthew G. Knepley }
38199bf0dad6SMatthew G. Knepley 
3820552f7358SJed Brown /*@C
3821eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3822552f7358SJed Brown 
3823552f7358SJed Brown   Not collective
3824552f7358SJed Brown 
3825552f7358SJed Brown   Input Parameters:
3826b5a892a1SMatthew G. Knepley + dm        - The DMPlex
3827b5a892a1SMatthew G. Knepley . p         - The mesh point
3828b5a892a1SMatthew G. Knepley . useCone   - PETSC_TRUE for the closure, otherwise return the star
3829b5a892a1SMatthew G. Knepley . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3830b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3831552f7358SJed Brown 
3832552f7358SJed Brown   Note:
38330298fd71SBarry Smith   If not using internal storage (points is not NULL on input), this call is unnecessary
3834552f7358SJed Brown 
3835552f7358SJed Brown   Level: beginner
3836552f7358SJed Brown 
3837db781477SPatrick Sanan .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3838552f7358SJed Brown @*/
3839d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3840d71ae5a4SJacob Faibussowitsch {
3841b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3842552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38434ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
38449566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
3845552f7358SJed Brown   PetscFunctionReturn(0);
3846552f7358SJed Brown }
3847552f7358SJed Brown 
3848552f7358SJed Brown /*@
3849eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3850552f7358SJed Brown 
3851552f7358SJed Brown   Not collective
3852552f7358SJed Brown 
3853552f7358SJed Brown   Input Parameter:
3854552f7358SJed Brown . mesh - The DMPlex
3855552f7358SJed Brown 
3856552f7358SJed Brown   Output Parameters:
3857552f7358SJed Brown + maxConeSize - The maximum number of in-edges
3858552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
3859552f7358SJed Brown 
3860552f7358SJed Brown   Level: beginner
3861552f7358SJed Brown 
3862db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3863552f7358SJed Brown @*/
3864d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3865d71ae5a4SJacob Faibussowitsch {
3866552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3867552f7358SJed Brown 
3868552f7358SJed Brown   PetscFunctionBegin;
3869552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38701baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
38711baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
3872552f7358SJed Brown   PetscFunctionReturn(0);
3873552f7358SJed Brown }
3874552f7358SJed Brown 
3875d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
3876d71ae5a4SJacob Faibussowitsch {
3877552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
38786302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
3879552f7358SJed Brown 
3880552f7358SJed Brown   PetscFunctionBegin;
3881552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38829566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
38839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
38849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
38859566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
38866302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
38876302a7fbSVaclav Hapla   if (maxSupportSize) {
38889566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
38899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
38909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
3891552f7358SJed Brown   }
3892552f7358SJed Brown   PetscFunctionReturn(0);
3893552f7358SJed Brown }
3894552f7358SJed Brown 
3895d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3896d71ae5a4SJacob Faibussowitsch {
3897552f7358SJed Brown   PetscFunctionBegin;
38989566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
38999566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3900ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
3901736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
390295602cf2SAlexis Marboeuf     PetscSF sfNatural;
3903f94b4a02SBlaise Bourdin 
39043dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
39059566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
390695602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
3907c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
3908f94b4a02SBlaise Bourdin   }
3909552f7358SJed Brown   PetscFunctionReturn(0);
3910552f7358SJed Brown }
3911552f7358SJed Brown 
3912d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3913d71ae5a4SJacob Faibussowitsch {
39143dcd263cSBlaise Bourdin   PetscInt i = 0;
39152adcc780SMatthew G. Knepley 
39162adcc780SMatthew G. Knepley   PetscFunctionBegin;
39179566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
39189566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
3919c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
39203dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
39213dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
392295602cf2SAlexis Marboeuf       PetscSF sfNatural;
39233dcd263cSBlaise Bourdin 
39243dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
39259566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
3926c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
392795602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
3928c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
39293dcd263cSBlaise Bourdin       break;
39303dcd263cSBlaise Bourdin     }
39313dcd263cSBlaise Bourdin   }
39322adcc780SMatthew G. Knepley   PetscFunctionReturn(0);
39332adcc780SMatthew G. Knepley }
39342adcc780SMatthew G. Knepley 
3935552f7358SJed Brown /*@
3936eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3937552f7358SJed Brown 
3938552f7358SJed Brown   Not collective
3939552f7358SJed Brown 
3940552f7358SJed Brown   Input Parameter:
3941552f7358SJed Brown . mesh - The DMPlex
3942552f7358SJed Brown 
3943552f7358SJed Brown   Output Parameter:
3944552f7358SJed Brown 
3945552f7358SJed Brown   Note:
3946552f7358SJed Brown   This should be called after all calls to DMPlexSetCone()
3947552f7358SJed Brown 
3948552f7358SJed Brown   Level: beginner
3949552f7358SJed Brown 
3950db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
3951552f7358SJed Brown @*/
3952d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
3953d71ae5a4SJacob Faibussowitsch {
3954552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
3955552f7358SJed Brown   PetscInt *offsets;
3956552f7358SJed Brown   PetscInt  supportSize;
3957552f7358SJed Brown   PetscInt  pStart, pEnd, p;
3958552f7358SJed Brown 
3959552f7358SJed Brown   PetscFunctionBegin;
3960552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
396128b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
39629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
3963552f7358SJed Brown   /* Calculate support sizes */
39649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3965552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
3966552f7358SJed Brown     PetscInt dof, off, c;
3967552f7358SJed Brown 
39689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
39699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
397048a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
3971552f7358SJed Brown   }
39729566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
3973552f7358SJed Brown   /* Calculate supports */
39749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
39759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
39769566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
3977552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
3978552f7358SJed Brown     PetscInt dof, off, c;
3979552f7358SJed Brown 
39809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
39819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3982552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
3983552f7358SJed Brown       const PetscInt q = mesh->cones[c];
3984552f7358SJed Brown       PetscInt       offS;
3985552f7358SJed Brown 
39869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
39870d644c17SKarl Rupp 
3988552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
3989552f7358SJed Brown       ++offsets[q];
3990552f7358SJed Brown     }
3991552f7358SJed Brown   }
39929566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
39939566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
3994552f7358SJed Brown   PetscFunctionReturn(0);
3995552f7358SJed Brown }
3996552f7358SJed Brown 
3997d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3998d71ae5a4SJacob Faibussowitsch {
3999277ea44aSLisandro Dalcin   IS stratumIS;
4000277ea44aSLisandro Dalcin 
4001277ea44aSLisandro Dalcin   PetscFunctionBegin;
4002277ea44aSLisandro Dalcin   if (pStart >= pEnd) PetscFunctionReturn(0);
400376bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4004277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4005277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
40069566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4007277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
40089566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
40099371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
40109371c9d4SSatish Balay         overlap = PETSC_TRUE;
40119371c9d4SSatish Balay         break;
40129371c9d4SSatish Balay       }
4013277ea44aSLisandro Dalcin     }
401463a3b9bcSJacob 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);
4015277ea44aSLisandro Dalcin   }
40169566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
40179566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
40189566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
4019277ea44aSLisandro Dalcin   PetscFunctionReturn(0);
4020277ea44aSLisandro Dalcin }
4021277ea44aSLisandro Dalcin 
4022552f7358SJed Brown /*@
4023a8d69d7bSBarry Smith   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
40246dd80730SBarry Smith   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
4025552f7358SJed Brown   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
4026552f7358SJed Brown   the DAG.
4027552f7358SJed Brown 
4028bf4602e4SToby Isaac   Collective on dm
4029552f7358SJed Brown 
4030552f7358SJed Brown   Input Parameter:
4031552f7358SJed Brown . mesh - The DMPlex
4032552f7358SJed Brown 
4033552f7358SJed Brown   Output Parameter:
4034552f7358SJed Brown 
4035552f7358SJed Brown   Notes:
4036b1bb481bSMatthew Knepley   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4037b1bb481bSMatthew 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
4038b1bb481bSMatthew Knepley   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
4039c58f1c22SToby Isaac   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4040150b719bSJed Brown   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
4041552f7358SJed Brown 
4042b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4043b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4044b1bb481bSMatthew 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
4045b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4046b1bb481bSMatthew Knepley $  cone(c0) = {e0, v2}
4047b1bb481bSMatthew Knepley $  cone(e0) = {v0, v1}
4048b1bb481bSMatthew Knepley   If DMPlexStratify() is run on this mesh, it will give depths
4049b1bb481bSMatthew Knepley $  depth 0 = {v0, v1, v2}
4050b1bb481bSMatthew Knepley $  depth 1 = {e0, c0}
4051b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4052b1bb481bSMatthew Knepley 
4053150b719bSJed Brown   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
4054552f7358SJed Brown 
4055552f7358SJed Brown   Level: beginner
4056552f7358SJed Brown 
4057db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4058552f7358SJed Brown @*/
4059d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4060d71ae5a4SJacob Faibussowitsch {
4061df0420ecSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
4062aa50250dSMatthew G. Knepley   DMLabel  label;
4063552f7358SJed Brown   PetscInt pStart, pEnd, p;
4064552f7358SJed Brown   PetscInt numRoots = 0, numLeaves = 0;
4065552f7358SJed Brown 
4066552f7358SJed Brown   PetscFunctionBegin;
4067552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40689566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4069277ea44aSLisandro Dalcin 
4070277ea44aSLisandro Dalcin   /* Create depth label */
40719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
40729566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
40739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4074277ea44aSLisandro Dalcin 
4075277ea44aSLisandro Dalcin   {
4076552f7358SJed Brown     /* Initialize roots and count leaves */
4077277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
4078277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
4079552f7358SJed Brown     PetscInt coneSize, supportSize;
4080552f7358SJed Brown 
4081277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
40829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
40839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4084552f7358SJed Brown       if (!coneSize && supportSize) {
4085277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
4086277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
4087552f7358SJed Brown         ++numRoots;
4088552f7358SJed Brown       } else if (!supportSize && coneSize) {
4089552f7358SJed Brown         ++numLeaves;
4090552f7358SJed Brown       } else if (!supportSize && !coneSize) {
4091552f7358SJed Brown         /* Isolated points */
4092277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
4093277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
4094552f7358SJed Brown       }
4095552f7358SJed Brown     }
40969566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4097277ea44aSLisandro Dalcin   }
4098277ea44aSLisandro Dalcin 
4099552f7358SJed Brown   if (numRoots + numLeaves == (pEnd - pStart)) {
4100277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
4101277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
4102552f7358SJed Brown     PetscInt coneSize, supportSize;
4103552f7358SJed Brown 
4104277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
41059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
41069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4107552f7358SJed Brown       if (!supportSize && coneSize) {
4108277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
4109277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
4110552f7358SJed Brown       }
4111552f7358SJed Brown     }
41129566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4113552f7358SJed Brown   } else {
4114277ea44aSLisandro Dalcin     PetscInt level = 0;
4115277ea44aSLisandro Dalcin     PetscInt qStart, qEnd, q;
4116552f7358SJed Brown 
41179566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4118277ea44aSLisandro Dalcin     while (qEnd > qStart) {
4119277ea44aSLisandro Dalcin       PetscInt sMin = PETSC_MAX_INT;
4120277ea44aSLisandro Dalcin       PetscInt sMax = PETSC_MIN_INT;
412174ef644bSMatthew G. Knepley 
4122277ea44aSLisandro Dalcin       for (q = qStart; q < qEnd; ++q) {
412374ef644bSMatthew G. Knepley         const PetscInt *support;
412474ef644bSMatthew G. Knepley         PetscInt        supportSize, s;
412574ef644bSMatthew G. Knepley 
41269566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
41279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, q, &support));
412874ef644bSMatthew G. Knepley         for (s = 0; s < supportSize; ++s) {
4129277ea44aSLisandro Dalcin           sMin = PetscMin(support[s], sMin);
4130277ea44aSLisandro Dalcin           sMax = PetscMax(support[s], sMax);
4131552f7358SJed Brown         }
4132552f7358SJed Brown       }
41339566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &level));
41349566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
41359566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
413674ef644bSMatthew G. Knepley     }
413774ef644bSMatthew G. Knepley   }
4138bf4602e4SToby Isaac   { /* just in case there is an empty process */
4139bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4140bf4602e4SToby Isaac 
41419566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
41429566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
414348a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4144bf4602e4SToby Isaac   }
41459566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
41469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
4147552f7358SJed Brown   PetscFunctionReturn(0);
4148552f7358SJed Brown }
4149552f7358SJed Brown 
4150d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4151d71ae5a4SJacob Faibussowitsch {
4152412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4153412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4154ba2698f1SMatthew G. Knepley 
4155412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
41569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
41579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
41589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4159ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4160ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4161ba2698f1SMatthew G. Knepley     switch (pdepth) {
4162d71ae5a4SJacob Faibussowitsch     case 0:
4163d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4164d71ae5a4SJacob Faibussowitsch       break;
4165ba2698f1SMatthew G. Knepley     case 1:
4166ba2698f1SMatthew G. Knepley       switch (coneSize) {
4167d71ae5a4SJacob Faibussowitsch       case 2:
4168d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4169d71ae5a4SJacob Faibussowitsch         break;
4170d71ae5a4SJacob Faibussowitsch       case 3:
4171d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4172d71ae5a4SJacob Faibussowitsch         break;
4173ba2698f1SMatthew G. Knepley       case 4:
4174ba2698f1SMatthew G. Knepley         switch (dim) {
4175d71ae5a4SJacob Faibussowitsch         case 2:
4176d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4177d71ae5a4SJacob Faibussowitsch           break;
4178d71ae5a4SJacob Faibussowitsch         case 3:
4179d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4180d71ae5a4SJacob Faibussowitsch           break;
4181d71ae5a4SJacob Faibussowitsch         default:
4182d71ae5a4SJacob Faibussowitsch           break;
4183ba2698f1SMatthew G. Knepley         }
4184ba2698f1SMatthew G. Knepley         break;
4185d71ae5a4SJacob Faibussowitsch       case 5:
4186d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4187d71ae5a4SJacob Faibussowitsch         break;
4188d71ae5a4SJacob Faibussowitsch       case 6:
4189d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4190d71ae5a4SJacob Faibussowitsch         break;
4191d71ae5a4SJacob Faibussowitsch       case 8:
4192d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4193d71ae5a4SJacob Faibussowitsch         break;
4194d71ae5a4SJacob Faibussowitsch       default:
4195d71ae5a4SJacob Faibussowitsch         break;
4196ba2698f1SMatthew G. Knepley       }
4197ba2698f1SMatthew G. Knepley     }
4198ba2698f1SMatthew G. Knepley   } else {
4199ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4200ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4201ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4202ba2698f1SMatthew G. Knepley       switch (dim) {
4203ba2698f1SMatthew G. Knepley       case 1:
4204ba2698f1SMatthew G. Knepley         switch (coneSize) {
4205d71ae5a4SJacob Faibussowitsch         case 2:
4206d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4207d71ae5a4SJacob Faibussowitsch           break;
4208d71ae5a4SJacob Faibussowitsch         default:
4209d71ae5a4SJacob Faibussowitsch           break;
4210ba2698f1SMatthew G. Knepley         }
4211ba2698f1SMatthew G. Knepley         break;
4212ba2698f1SMatthew G. Knepley       case 2:
4213ba2698f1SMatthew G. Knepley         switch (coneSize) {
4214d71ae5a4SJacob Faibussowitsch         case 3:
4215d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4216d71ae5a4SJacob Faibussowitsch           break;
4217d71ae5a4SJacob Faibussowitsch         case 4:
4218d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4219d71ae5a4SJacob Faibussowitsch           break;
4220d71ae5a4SJacob Faibussowitsch         default:
4221d71ae5a4SJacob Faibussowitsch           break;
4222ba2698f1SMatthew G. Knepley         }
4223ba2698f1SMatthew G. Knepley         break;
4224ba2698f1SMatthew G. Knepley       case 3:
4225ba2698f1SMatthew G. Knepley         switch (coneSize) {
4226d71ae5a4SJacob Faibussowitsch         case 4:
4227d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4228d71ae5a4SJacob Faibussowitsch           break;
42299371c9d4SSatish Balay         case 5: {
4230da9060c4SMatthew G. Knepley           const PetscInt *cone;
4231da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4232da9060c4SMatthew G. Knepley 
42339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
42349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4235da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4236d71ae5a4SJacob Faibussowitsch           case 3:
4237d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4238d71ae5a4SJacob Faibussowitsch             break;
4239d71ae5a4SJacob Faibussowitsch           case 4:
4240d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4241d71ae5a4SJacob Faibussowitsch             break;
4242da9060c4SMatthew G. Knepley           }
42439371c9d4SSatish Balay         } break;
4244d71ae5a4SJacob Faibussowitsch         case 6:
4245d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4246d71ae5a4SJacob Faibussowitsch           break;
4247d71ae5a4SJacob Faibussowitsch         default:
4248d71ae5a4SJacob Faibussowitsch           break;
4249ba2698f1SMatthew G. Knepley         }
4250ba2698f1SMatthew G. Knepley         break;
4251d71ae5a4SJacob Faibussowitsch       default:
4252d71ae5a4SJacob Faibussowitsch         break;
4253ba2698f1SMatthew G. Knepley       }
4254ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4255ba2698f1SMatthew G. Knepley       switch (coneSize) {
4256d71ae5a4SJacob Faibussowitsch       case 2:
4257d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4258d71ae5a4SJacob Faibussowitsch         break;
4259d71ae5a4SJacob Faibussowitsch       case 3:
4260d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4261d71ae5a4SJacob Faibussowitsch         break;
4262d71ae5a4SJacob Faibussowitsch       case 4:
4263d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4264d71ae5a4SJacob Faibussowitsch         break;
4265d71ae5a4SJacob Faibussowitsch       default:
4266d71ae5a4SJacob Faibussowitsch         break;
4267ba2698f1SMatthew G. Knepley       }
4268ba2698f1SMatthew G. Knepley     }
4269ba2698f1SMatthew G. Knepley   }
4270412e9a14SMatthew G. Knepley   *pt = ct;
4271412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
4272ba2698f1SMatthew G. Knepley }
4273412e9a14SMatthew G. Knepley 
4274412e9a14SMatthew G. Knepley /*@
4275412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4276412e9a14SMatthew G. Knepley 
4277412e9a14SMatthew G. Knepley   Collective on dm
4278412e9a14SMatthew G. Knepley 
4279412e9a14SMatthew G. Knepley   Input Parameter:
4280412e9a14SMatthew G. Knepley . mesh - The DMPlex
4281412e9a14SMatthew G. Knepley 
4282412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4283412e9a14SMatthew G. Knepley 
4284412e9a14SMatthew G. Knepley   Level: developer
4285412e9a14SMatthew G. Knepley 
4286412e9a14SMatthew G. Knepley   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4287412e9a14SMatthew G. Knepley   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4288412e9a14SMatthew G. Knepley   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4289412e9a14SMatthew G. Knepley 
4290db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4291412e9a14SMatthew G. Knepley @*/
4292d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4293d71ae5a4SJacob Faibussowitsch {
4294412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4295412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4296412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4297412e9a14SMatthew G. Knepley 
4298412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4299412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4300412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
43019566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
43029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
43039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4304412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4305327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4306412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4307412e9a14SMatthew G. Knepley 
43089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
43099566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
431063a3b9bcSJacob Faibussowitsch     PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p);
43119566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4312412e9a14SMatthew G. Knepley   }
43139566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
43149566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
4315ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4316ba2698f1SMatthew G. Knepley }
4317ba2698f1SMatthew G. Knepley 
4318552f7358SJed Brown /*@C
4319552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4320552f7358SJed Brown 
4321552f7358SJed Brown   Not Collective
4322552f7358SJed Brown 
4323552f7358SJed Brown   Input Parameters:
4324552f7358SJed Brown + dm - The DMPlex object
4325552f7358SJed Brown . numPoints - The number of input points for the join
4326552f7358SJed Brown - points - The input points
4327552f7358SJed Brown 
4328552f7358SJed Brown   Output Parameters:
4329552f7358SJed Brown + numCoveredPoints - The number of points in the join
4330552f7358SJed Brown - coveredPoints - The points in the join
4331552f7358SJed Brown 
4332552f7358SJed Brown   Level: intermediate
4333552f7358SJed Brown 
4334552f7358SJed Brown   Note: Currently, this is restricted to a single level join
4335552f7358SJed Brown 
43363813dfbdSMatthew G Knepley   Fortran Notes:
43373813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
43383813dfbdSMatthew G Knepley   include petsc.h90 in your code.
43393813dfbdSMatthew G Knepley 
43403813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
43413813dfbdSMatthew G Knepley 
4342db781477SPatrick Sanan .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4343552f7358SJed Brown @*/
4344d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4345d71ae5a4SJacob Faibussowitsch {
4346552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4347552f7358SJed Brown   PetscInt *join[2];
4348552f7358SJed Brown   PetscInt  joinSize, i = 0;
4349552f7358SJed Brown   PetscInt  dof, off, p, c, m;
43506302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4351552f7358SJed Brown 
4352552f7358SJed Brown   PetscFunctionBegin;
4353552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
435448bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
435548bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
435648bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
43576302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
43586302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
43596302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4360552f7358SJed Brown   /* Copy in support of first point */
43619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
43629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4363ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4364552f7358SJed Brown   /* Check each successive support */
4365552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4366552f7358SJed Brown     PetscInt newJoinSize = 0;
4367552f7358SJed Brown 
43689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
43699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4370552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4371552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4372552f7358SJed Brown 
4373552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4374552f7358SJed Brown         if (point == join[i][m]) {
4375552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4376552f7358SJed Brown           break;
4377552f7358SJed Brown         }
4378552f7358SJed Brown       }
4379552f7358SJed Brown     }
4380552f7358SJed Brown     joinSize = newJoinSize;
4381552f7358SJed Brown     i        = 1 - i;
4382552f7358SJed Brown   }
4383552f7358SJed Brown   *numCoveredPoints = joinSize;
4384552f7358SJed Brown   *coveredPoints    = join[i];
43856302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
4386552f7358SJed Brown   PetscFunctionReturn(0);
4387552f7358SJed Brown }
4388552f7358SJed Brown 
4389552f7358SJed Brown /*@C
4390552f7358SJed Brown   DMPlexRestoreJoin - Restore an array for the join of the set of points
4391552f7358SJed Brown 
4392552f7358SJed Brown   Not Collective
4393552f7358SJed Brown 
4394552f7358SJed Brown   Input Parameters:
4395552f7358SJed Brown + dm - The DMPlex object
4396552f7358SJed Brown . numPoints - The number of input points for the join
4397552f7358SJed Brown - points - The input points
4398552f7358SJed Brown 
4399552f7358SJed Brown   Output Parameters:
4400552f7358SJed Brown + numCoveredPoints - The number of points in the join
4401552f7358SJed Brown - coveredPoints - The points in the join
4402552f7358SJed Brown 
44033813dfbdSMatthew G Knepley   Fortran Notes:
44043813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
44053813dfbdSMatthew G Knepley   include petsc.h90 in your code.
44063813dfbdSMatthew G Knepley 
44073813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
44083813dfbdSMatthew G Knepley 
4409552f7358SJed Brown   Level: intermediate
4410552f7358SJed Brown 
4411db781477SPatrick Sanan .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4412552f7358SJed Brown @*/
4413d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4414d71ae5a4SJacob Faibussowitsch {
4415552f7358SJed Brown   PetscFunctionBegin;
4416552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4417d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points, 3);
4418d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4);
4419d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints, 5);
44209566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4421d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
4422552f7358SJed Brown   PetscFunctionReturn(0);
4423552f7358SJed Brown }
4424552f7358SJed Brown 
4425552f7358SJed Brown /*@C
4426552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4427552f7358SJed Brown 
4428552f7358SJed Brown   Not Collective
4429552f7358SJed Brown 
4430552f7358SJed Brown   Input Parameters:
4431552f7358SJed Brown + dm - The DMPlex object
4432552f7358SJed Brown . numPoints - The number of input points for the join
4433552f7358SJed Brown - points - The input points
4434552f7358SJed Brown 
4435552f7358SJed Brown   Output Parameters:
4436552f7358SJed Brown + numCoveredPoints - The number of points in the join
4437552f7358SJed Brown - coveredPoints - The points in the join
4438552f7358SJed Brown 
44393813dfbdSMatthew G Knepley   Fortran Notes:
44403813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
44413813dfbdSMatthew G Knepley   include petsc.h90 in your code.
44423813dfbdSMatthew G Knepley 
44433813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
44443813dfbdSMatthew G Knepley 
4445552f7358SJed Brown   Level: intermediate
4446552f7358SJed Brown 
4447db781477SPatrick Sanan .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4448552f7358SJed Brown @*/
4449d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4450d71ae5a4SJacob Faibussowitsch {
4451552f7358SJed Brown   PetscInt *offsets, **closures;
4452552f7358SJed Brown   PetscInt *join[2];
4453552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
445424c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4455552f7358SJed Brown 
4456552f7358SJed Brown   PetscFunctionBegin;
4457552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
445848bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
445948bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
446048bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
4461552f7358SJed Brown 
44629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
44639566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
44649566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
44656302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
446624c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
44679566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
44689566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4469552f7358SJed Brown 
4470552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4471552f7358SJed Brown     PetscInt closureSize;
4472552f7358SJed Brown 
44739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
44740d644c17SKarl Rupp 
4475552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4476552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4477552f7358SJed Brown       PetscInt pStart, pEnd, i;
4478552f7358SJed Brown 
44799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4480552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4481552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4482552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4483552f7358SJed Brown           break;
4484552f7358SJed Brown         }
4485552f7358SJed Brown       }
4486552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4487552f7358SJed Brown     }
448863a3b9bcSJacob 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);
4489552f7358SJed Brown   }
4490552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4491552f7358SJed Brown     PetscInt dof;
4492552f7358SJed Brown 
4493552f7358SJed Brown     /* Copy in support of first point */
4494552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4495ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4496552f7358SJed Brown     /* Check each successive cone */
4497552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4498552f7358SJed Brown       PetscInt newJoinSize = 0;
4499552f7358SJed Brown 
4500552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
4501552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4502552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
4503552f7358SJed Brown 
4504552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4505552f7358SJed Brown           if (point == join[i][m]) {
4506552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
4507552f7358SJed Brown             break;
4508552f7358SJed Brown           }
4509552f7358SJed Brown         }
4510552f7358SJed Brown       }
4511552f7358SJed Brown       joinSize = newJoinSize;
4512552f7358SJed Brown       i        = 1 - i;
4513552f7358SJed Brown     }
4514552f7358SJed Brown     if (joinSize) break;
4515552f7358SJed Brown   }
4516552f7358SJed Brown   *numCoveredPoints = joinSize;
4517552f7358SJed Brown   *coveredPoints    = join[i];
451848a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
45199566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
45209566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
45216302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
4522552f7358SJed Brown   PetscFunctionReturn(0);
4523552f7358SJed Brown }
4524552f7358SJed Brown 
4525552f7358SJed Brown /*@C
4526552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4527552f7358SJed Brown 
4528552f7358SJed Brown   Not Collective
4529552f7358SJed Brown 
4530552f7358SJed Brown   Input Parameters:
4531552f7358SJed Brown + dm - The DMPlex object
4532552f7358SJed Brown . numPoints - The number of input points for the meet
4533552f7358SJed Brown - points - The input points
4534552f7358SJed Brown 
4535552f7358SJed Brown   Output Parameters:
4536552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4537552f7358SJed Brown - coveredPoints - The points in the meet
4538552f7358SJed Brown 
4539552f7358SJed Brown   Level: intermediate
4540552f7358SJed Brown 
4541552f7358SJed Brown   Note: Currently, this is restricted to a single level meet
4542552f7358SJed Brown 
45433813dfbdSMatthew G Knepley   Fortran Notes:
45443813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
45453813dfbdSMatthew G Knepley   include petsc.h90 in your code.
45463813dfbdSMatthew G Knepley 
45473813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
45483813dfbdSMatthew G Knepley 
4549db781477SPatrick Sanan .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4550552f7358SJed Brown @*/
4551d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4552d71ae5a4SJacob Faibussowitsch {
4553552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4554552f7358SJed Brown   PetscInt *meet[2];
4555552f7358SJed Brown   PetscInt  meetSize, i = 0;
4556552f7358SJed Brown   PetscInt  dof, off, p, c, m;
45576302a7fbSVaclav Hapla   PetscInt  maxConeSize;
4558552f7358SJed Brown 
4559552f7358SJed Brown   PetscFunctionBegin;
4560552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4561dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4562dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveringPoints, 4);
4563064a246eSJacob Faibussowitsch   PetscValidPointer(coveringPoints, 5);
45646302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
45656302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
45666302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4567552f7358SJed Brown   /* Copy in cone of first point */
45689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
45699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4570ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4571552f7358SJed Brown   /* Check each successive cone */
4572552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4573552f7358SJed Brown     PetscInt newMeetSize = 0;
4574552f7358SJed Brown 
45759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
45769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4577552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4578552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
4579552f7358SJed Brown 
4580552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
4581552f7358SJed Brown         if (point == meet[i][m]) {
4582552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
4583552f7358SJed Brown           break;
4584552f7358SJed Brown         }
4585552f7358SJed Brown       }
4586552f7358SJed Brown     }
4587552f7358SJed Brown     meetSize = newMeetSize;
4588552f7358SJed Brown     i        = 1 - i;
4589552f7358SJed Brown   }
4590552f7358SJed Brown   *numCoveringPoints = meetSize;
4591552f7358SJed Brown   *coveringPoints    = meet[i];
45926302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
4593552f7358SJed Brown   PetscFunctionReturn(0);
4594552f7358SJed Brown }
4595552f7358SJed Brown 
4596552f7358SJed Brown /*@C
4597552f7358SJed Brown   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4598552f7358SJed Brown 
4599552f7358SJed Brown   Not Collective
4600552f7358SJed Brown 
4601552f7358SJed Brown   Input Parameters:
4602552f7358SJed Brown + dm - The DMPlex object
4603552f7358SJed Brown . numPoints - The number of input points for the meet
4604552f7358SJed Brown - points - The input points
4605552f7358SJed Brown 
4606552f7358SJed Brown   Output Parameters:
4607552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4608552f7358SJed Brown - coveredPoints - The points in the meet
4609552f7358SJed Brown 
4610552f7358SJed Brown   Level: intermediate
4611552f7358SJed Brown 
46123813dfbdSMatthew G Knepley   Fortran Notes:
46133813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
46143813dfbdSMatthew G Knepley   include petsc.h90 in your code.
46153813dfbdSMatthew G Knepley 
46163813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
46173813dfbdSMatthew G Knepley 
4618db781477SPatrick Sanan .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4619552f7358SJed Brown @*/
4620d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4621d71ae5a4SJacob Faibussowitsch {
4622552f7358SJed Brown   PetscFunctionBegin;
4623552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4624d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points, 3);
4625d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4);
4626d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints, 5);
46279566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4628d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
4629552f7358SJed Brown   PetscFunctionReturn(0);
4630552f7358SJed Brown }
4631552f7358SJed Brown 
4632552f7358SJed Brown /*@C
4633552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
4634552f7358SJed Brown 
4635552f7358SJed Brown   Not Collective
4636552f7358SJed Brown 
4637552f7358SJed Brown   Input Parameters:
4638552f7358SJed Brown + dm - The DMPlex object
4639552f7358SJed Brown . numPoints - The number of input points for the meet
4640552f7358SJed Brown - points - The input points
4641552f7358SJed Brown 
4642552f7358SJed Brown   Output Parameters:
4643552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4644552f7358SJed Brown - coveredPoints - The points in the meet
4645552f7358SJed Brown 
4646552f7358SJed Brown   Level: intermediate
4647552f7358SJed Brown 
46483813dfbdSMatthew G Knepley   Fortran Notes:
46493813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
46503813dfbdSMatthew G Knepley   include petsc.h90 in your code.
46513813dfbdSMatthew G Knepley 
46523813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
46533813dfbdSMatthew G Knepley 
4654db781477SPatrick Sanan .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4655552f7358SJed Brown @*/
4656d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4657d71ae5a4SJacob Faibussowitsch {
4658552f7358SJed Brown   PetscInt *offsets, **closures;
4659552f7358SJed Brown   PetscInt *meet[2];
4660552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
466124c766afSToby Isaac   PetscInt  p, h, c, m, mc;
4662552f7358SJed Brown 
4663552f7358SJed Brown   PetscFunctionBegin;
4664552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4665dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4666dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveredPoints, 4);
4667064a246eSJacob Faibussowitsch   PetscValidPointer(coveredPoints, 5);
4668552f7358SJed Brown 
46699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
46709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
46719566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
46726302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
467324c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
46749566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
46759566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4676552f7358SJed Brown 
4677552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4678552f7358SJed Brown     PetscInt closureSize;
4679552f7358SJed Brown 
46809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
46810d644c17SKarl Rupp 
4682552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
4683552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
4684552f7358SJed Brown       PetscInt pStart, pEnd, i;
4685552f7358SJed Brown 
46869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4687552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
4688552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4689552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
4690552f7358SJed Brown           break;
4691552f7358SJed Brown         }
4692552f7358SJed Brown       }
4693552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
4694552f7358SJed Brown     }
469563a3b9bcSJacob 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);
4696552f7358SJed Brown   }
4697552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
4698552f7358SJed Brown     PetscInt dof;
4699552f7358SJed Brown 
4700552f7358SJed Brown     /* Copy in cone of first point */
4701552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
4702ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
4703552f7358SJed Brown     /* Check each successive cone */
4704552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
4705552f7358SJed Brown       PetscInt newMeetSize = 0;
4706552f7358SJed Brown 
4707552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
4708552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4709552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
4710552f7358SJed Brown 
4711552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
4712552f7358SJed Brown           if (point == meet[i][m]) {
4713552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
4714552f7358SJed Brown             break;
4715552f7358SJed Brown           }
4716552f7358SJed Brown         }
4717552f7358SJed Brown       }
4718552f7358SJed Brown       meetSize = newMeetSize;
4719552f7358SJed Brown       i        = 1 - i;
4720552f7358SJed Brown     }
4721552f7358SJed Brown     if (meetSize) break;
4722552f7358SJed Brown   }
4723552f7358SJed Brown   *numCoveredPoints = meetSize;
4724552f7358SJed Brown   *coveredPoints    = meet[i];
472548a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
47269566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
47279566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
47286302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
4729552f7358SJed Brown   PetscFunctionReturn(0);
4730552f7358SJed Brown }
4731552f7358SJed Brown 
47324e3744c5SMatthew G. Knepley /*@C
47334e3744c5SMatthew G. Knepley   DMPlexEqual - Determine if two DMs have the same topology
47344e3744c5SMatthew G. Knepley 
47354e3744c5SMatthew G. Knepley   Not Collective
47364e3744c5SMatthew G. Knepley 
47374e3744c5SMatthew G. Knepley   Input Parameters:
47384e3744c5SMatthew G. Knepley + dmA - A DMPlex object
47394e3744c5SMatthew G. Knepley - dmB - A DMPlex object
47404e3744c5SMatthew G. Knepley 
47414e3744c5SMatthew G. Knepley   Output Parameters:
47424e3744c5SMatthew G. Knepley . equal - PETSC_TRUE if the topologies are identical
47434e3744c5SMatthew G. Knepley 
47444e3744c5SMatthew G. Knepley   Level: intermediate
47454e3744c5SMatthew G. Knepley 
47464e3744c5SMatthew G. Knepley   Notes:
47474e3744c5SMatthew G. Knepley   We are not solving graph isomorphism, so we do not permutation.
47484e3744c5SMatthew G. Knepley 
4749db781477SPatrick Sanan .seealso: `DMPlexGetCone()`
47504e3744c5SMatthew G. Knepley @*/
4751d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4752d71ae5a4SJacob Faibussowitsch {
47534e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
47544e3744c5SMatthew G. Knepley 
47554e3744c5SMatthew G. Knepley   PetscFunctionBegin;
47564e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
47574e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4758dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(equal, 3);
47594e3744c5SMatthew G. Knepley 
47604e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
47619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
47629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
47634e3744c5SMatthew G. Knepley   if (depth != depthB) PetscFunctionReturn(0);
47649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
47659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
47664e3744c5SMatthew G. Knepley   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
47674e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
47684e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
47694e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
47704e3744c5SMatthew G. Knepley 
47719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
47729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
47739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
47749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
47759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
47769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
47774e3744c5SMatthew G. Knepley     if (coneSize != coneSizeB) PetscFunctionReturn(0);
47784e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
47794e3744c5SMatthew G. Knepley       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
47804e3744c5SMatthew G. Knepley       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
47814e3744c5SMatthew G. Knepley     }
47829566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
47839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
47849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
47859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
47864e3744c5SMatthew G. Knepley     if (supportSize != supportSizeB) PetscFunctionReturn(0);
47874e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
47884e3744c5SMatthew G. Knepley       if (support[s] != supportB[s]) PetscFunctionReturn(0);
47894e3744c5SMatthew G. Knepley     }
47904e3744c5SMatthew G. Knepley   }
47914e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
47924e3744c5SMatthew G. Knepley   PetscFunctionReturn(0);
47934e3744c5SMatthew G. Knepley }
47944e3744c5SMatthew G. Knepley 
47957cd05799SMatthew G. Knepley /*@C
47967cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
47977cd05799SMatthew G. Knepley 
47987cd05799SMatthew G. Knepley   Not Collective
47997cd05799SMatthew G. Knepley 
48007cd05799SMatthew G. Knepley   Input Parameters:
48017cd05799SMatthew G. Knepley + dm         - The DMPlex
48027cd05799SMatthew G. Knepley . cellDim    - The cell dimension
48037cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
48047cd05799SMatthew G. Knepley 
48057cd05799SMatthew G. Knepley   Output Parameters:
48067cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
48077cd05799SMatthew G. Knepley 
48087cd05799SMatthew G. Knepley   Level: developer
48097cd05799SMatthew G. Knepley 
48107cd05799SMatthew G. Knepley   Notes:
48117cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
48127cd05799SMatthew G. Knepley 
4813db781477SPatrick Sanan .seealso: `DMPlexGetCone()`
48147cd05799SMatthew G. Knepley @*/
4815d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4816d71ae5a4SJacob Faibussowitsch {
481782f516ccSBarry Smith   MPI_Comm comm;
4818552f7358SJed Brown 
4819552f7358SJed Brown   PetscFunctionBegin;
48209566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4821dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numFaceVertices, 4);
4822552f7358SJed Brown   switch (cellDim) {
4823d71ae5a4SJacob Faibussowitsch   case 0:
4824d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
4825d71ae5a4SJacob Faibussowitsch     break;
4826d71ae5a4SJacob Faibussowitsch   case 1:
4827d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
4828d71ae5a4SJacob Faibussowitsch     break;
4829552f7358SJed Brown   case 2:
4830552f7358SJed Brown     switch (numCorners) {
483119436ca2SJed Brown     case 3:                 /* triangle */
483219436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4833552f7358SJed Brown       break;
483419436ca2SJed Brown     case 4:                 /* quadrilateral */
483519436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4836552f7358SJed Brown       break;
483719436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
483819436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4839552f7358SJed Brown       break;
484019436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
484119436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4842552f7358SJed Brown       break;
4843d71ae5a4SJacob Faibussowitsch     default:
4844d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4845552f7358SJed Brown     }
4846552f7358SJed Brown     break;
4847552f7358SJed Brown   case 3:
4848552f7358SJed Brown     switch (numCorners) {
484919436ca2SJed Brown     case 4:                 /* tetradehdron */
485019436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
4851552f7358SJed Brown       break;
485219436ca2SJed Brown     case 6:                 /* tet cohesive cells */
485319436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4854552f7358SJed Brown       break;
485519436ca2SJed Brown     case 8:                 /* hexahedron */
485619436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4857552f7358SJed Brown       break;
485819436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
485919436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4860552f7358SJed Brown       break;
486119436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
486219436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4863552f7358SJed Brown       break;
486419436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
486519436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4866552f7358SJed Brown       break;
486719436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
486819436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4869552f7358SJed Brown       break;
487019436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
487119436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
4872552f7358SJed Brown       break;
4873d71ae5a4SJacob Faibussowitsch     default:
4874d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4875552f7358SJed Brown     }
4876552f7358SJed Brown     break;
4877d71ae5a4SJacob Faibussowitsch   default:
4878d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
4879552f7358SJed Brown   }
4880552f7358SJed Brown   PetscFunctionReturn(0);
4881552f7358SJed Brown }
4882552f7358SJed Brown 
4883552f7358SJed Brown /*@
4884aa50250dSMatthew G. Knepley   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4885552f7358SJed Brown 
4886552f7358SJed Brown   Not Collective
4887552f7358SJed Brown 
4888aa50250dSMatthew G. Knepley   Input Parameter:
4889552f7358SJed Brown . dm    - The DMPlex object
4890552f7358SJed Brown 
4891aa50250dSMatthew G. Knepley   Output Parameter:
4892aa50250dSMatthew G. Knepley . depthLabel - The DMLabel recording point depth
4893552f7358SJed Brown 
4894552f7358SJed Brown   Level: developer
4895552f7358SJed Brown 
4896db781477SPatrick Sanan .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
4897aa50250dSMatthew G. Knepley @*/
4898d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4899d71ae5a4SJacob Faibussowitsch {
4900aa50250dSMatthew G. Knepley   PetscFunctionBegin;
4901aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4902aa50250dSMatthew G. Knepley   PetscValidPointer(depthLabel, 2);
4903c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
4904aa50250dSMatthew G. Knepley   PetscFunctionReturn(0);
4905aa50250dSMatthew G. Knepley }
4906aa50250dSMatthew G. Knepley 
4907aa50250dSMatthew G. Knepley /*@
4908aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4909aa50250dSMatthew G. Knepley 
4910aa50250dSMatthew G. Knepley   Not Collective
4911aa50250dSMatthew G. Knepley 
4912aa50250dSMatthew G. Knepley   Input Parameter:
4913aa50250dSMatthew G. Knepley . dm    - The DMPlex object
4914aa50250dSMatthew G. Knepley 
4915aa50250dSMatthew G. Knepley   Output Parameter:
4916aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
4917aa50250dSMatthew G. Knepley 
4918aa50250dSMatthew G. Knepley   Level: developer
4919552f7358SJed Brown 
4920b1bb481bSMatthew Knepley   Notes:
4921b1bb481bSMatthew Knepley   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4922dc287ab2SVaclav Hapla   The point depth is described more in detail in DMPlexGetDepthStratum().
4923dc287ab2SVaclav Hapla   An empty mesh gives -1.
4924b1bb481bSMatthew Knepley 
4925db781477SPatrick Sanan .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
4926552f7358SJed Brown @*/
4927d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4928d71ae5a4SJacob Faibussowitsch {
4929*9f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
4930aa50250dSMatthew G. Knepley   DMLabel  label;
4931aa50250dSMatthew G. Knepley   PetscInt d = 0;
4932552f7358SJed Brown 
4933552f7358SJed Brown   PetscFunctionBegin;
4934552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4935dadcf809SJacob Faibussowitsch   PetscValidIntPointer(depth, 2);
4936*9f4ada15SMatthew G. Knepley   if (mesh->tr) {
4937*9f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
4938*9f4ada15SMatthew G. Knepley   } else {
49399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
49409566063dSJacob Faibussowitsch     if (label) PetscCall(DMLabelGetNumValues(label, &d));
4941552f7358SJed Brown     *depth = d - 1;
4942*9f4ada15SMatthew G. Knepley   }
4943552f7358SJed Brown   PetscFunctionReturn(0);
4944552f7358SJed Brown }
4945552f7358SJed Brown 
4946552f7358SJed Brown /*@
4947552f7358SJed Brown   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4948552f7358SJed Brown 
4949552f7358SJed Brown   Not Collective
4950552f7358SJed Brown 
4951552f7358SJed Brown   Input Parameters:
4952552f7358SJed Brown + dm    - The DMPlex object
4953570fa34dSVaclav Hapla - depth - The requested depth
4954552f7358SJed Brown 
4955552f7358SJed Brown   Output Parameters:
4956552f7358SJed Brown + start - The first point at this depth
4957552f7358SJed Brown - end   - One beyond the last point at this depth
4958552f7358SJed Brown 
4959647867b2SJed Brown   Notes:
4960647867b2SJed Brown   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4961647867b2SJed Brown   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4962647867b2SJed Brown   higher dimension, e.g., "edges".
4963647867b2SJed Brown 
4964552f7358SJed Brown   Level: developer
4965552f7358SJed Brown 
4966db781477SPatrick Sanan .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
4967552f7358SJed Brown @*/
4968d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
4969d71ae5a4SJacob Faibussowitsch {
4970*9f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
4971aa50250dSMatthew G. Knepley   DMLabel  label;
497263d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
4973552f7358SJed Brown 
4974552f7358SJed Brown   PetscFunctionBegin;
4975552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49769371c9d4SSatish Balay   if (start) {
49779371c9d4SSatish Balay     PetscValidIntPointer(start, 3);
49789371c9d4SSatish Balay     *start = 0;
49799371c9d4SSatish Balay   }
49809371c9d4SSatish Balay   if (end) {
49819371c9d4SSatish Balay     PetscValidIntPointer(end, 4);
49829371c9d4SSatish Balay     *end = 0;
49839371c9d4SSatish Balay   }
49849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
49850d644c17SKarl Rupp   if (pStart == pEnd) PetscFunctionReturn(0);
4986570fa34dSVaclav Hapla   if (depth < 0) {
498763d1a920SMatthew G. Knepley     if (start) *start = pStart;
498863d1a920SMatthew G. Knepley     if (end) *end = pEnd;
498963d1a920SMatthew G. Knepley     PetscFunctionReturn(0);
4990552f7358SJed Brown   }
4991*9f4ada15SMatthew G. Knepley   if (mesh->tr) {
4992*9f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
4993*9f4ada15SMatthew G. Knepley   } else {
49949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
499528b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4996570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
4997*9f4ada15SMatthew G. Knepley   }
4998552f7358SJed Brown   PetscFunctionReturn(0);
4999552f7358SJed Brown }
5000552f7358SJed Brown 
5001552f7358SJed Brown /*@
5002552f7358SJed Brown   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
5003552f7358SJed Brown 
5004552f7358SJed Brown   Not Collective
5005552f7358SJed Brown 
5006552f7358SJed Brown   Input Parameters:
5007552f7358SJed Brown + dm     - The DMPlex object
5008570fa34dSVaclav Hapla - height - The requested height
5009552f7358SJed Brown 
5010552f7358SJed Brown   Output Parameters:
5011552f7358SJed Brown + start - The first point at this height
5012552f7358SJed Brown - end   - One beyond the last point at this height
5013552f7358SJed Brown 
5014647867b2SJed Brown   Notes:
5015647867b2SJed Brown   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5016647867b2SJed Brown   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
5017647867b2SJed Brown   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5018647867b2SJed Brown 
5019552f7358SJed Brown   Level: developer
5020552f7358SJed Brown 
5021db781477SPatrick Sanan .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5022552f7358SJed Brown @*/
5023d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5024d71ae5a4SJacob Faibussowitsch {
5025aa50250dSMatthew G. Knepley   DMLabel  label;
502663d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5027552f7358SJed Brown 
5028552f7358SJed Brown   PetscFunctionBegin;
5029552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50309371c9d4SSatish Balay   if (start) {
50319371c9d4SSatish Balay     PetscValidIntPointer(start, 3);
50329371c9d4SSatish Balay     *start = 0;
50339371c9d4SSatish Balay   }
50349371c9d4SSatish Balay   if (end) {
50359371c9d4SSatish Balay     PetscValidIntPointer(end, 4);
50369371c9d4SSatish Balay     *end = 0;
50379371c9d4SSatish Balay   }
50389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
50390d644c17SKarl Rupp   if (pStart == pEnd) PetscFunctionReturn(0);
5040570fa34dSVaclav Hapla   if (height < 0) {
504163d1a920SMatthew G. Knepley     if (start) *start = pStart;
504263d1a920SMatthew G. Knepley     if (end) *end = pEnd;
504363d1a920SMatthew G. Knepley     PetscFunctionReturn(0);
5044552f7358SJed Brown   }
50459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
504628b400f6SJacob Faibussowitsch   PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
50479566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(label, &depth));
5048570fa34dSVaclav Hapla   PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end));
5049552f7358SJed Brown   PetscFunctionReturn(0);
5050552f7358SJed Brown }
5051552f7358SJed Brown 
5052ba2698f1SMatthew G. Knepley /*@
5053ba2698f1SMatthew G. Knepley   DMPlexGetPointDepth - Get the depth of a given point
5054ba2698f1SMatthew G. Knepley 
5055ba2698f1SMatthew G. Knepley   Not Collective
5056ba2698f1SMatthew G. Knepley 
5057d8d19677SJose E. Roman   Input Parameters:
5058ba2698f1SMatthew G. Knepley + dm    - The DMPlex object
5059ba2698f1SMatthew G. Knepley - point - The point
5060ba2698f1SMatthew G. Knepley 
5061ba2698f1SMatthew G. Knepley   Output Parameter:
5062ba2698f1SMatthew G. Knepley . depth - The depth of the point
5063ba2698f1SMatthew G. Knepley 
5064ba2698f1SMatthew G. Knepley   Level: intermediate
5065ba2698f1SMatthew G. Knepley 
5066db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5067ba2698f1SMatthew G. Knepley @*/
5068d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5069d71ae5a4SJacob Faibussowitsch {
5070ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5071ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
507240a2aa30SMatthew G. Knepley   PetscValidIntPointer(depth, 3);
50739566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
5074ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
5075ba2698f1SMatthew G. Knepley }
5076ba2698f1SMatthew G. Knepley 
5077ba2698f1SMatthew G. Knepley /*@
50780c0a32dcSVaclav Hapla   DMPlexGetPointHeight - Get the height of a given point
50790c0a32dcSVaclav Hapla 
50800c0a32dcSVaclav Hapla   Not Collective
50810c0a32dcSVaclav Hapla 
5082d8d19677SJose E. Roman   Input Parameters:
50830c0a32dcSVaclav Hapla + dm    - The DMPlex object
50840c0a32dcSVaclav Hapla - point - The point
50850c0a32dcSVaclav Hapla 
50860c0a32dcSVaclav Hapla   Output Parameter:
50870c0a32dcSVaclav Hapla . height - The height of the point
50880c0a32dcSVaclav Hapla 
50890c0a32dcSVaclav Hapla   Level: intermediate
50900c0a32dcSVaclav Hapla 
5091db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
50920c0a32dcSVaclav Hapla @*/
5093d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5094d71ae5a4SJacob Faibussowitsch {
50950c0a32dcSVaclav Hapla   PetscInt n, pDepth;
50960c0a32dcSVaclav Hapla 
50970c0a32dcSVaclav Hapla   PetscFunctionBegin;
50980c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50990c0a32dcSVaclav Hapla   PetscValidIntPointer(height, 3);
51009566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
51019566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
51020c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
51030c0a32dcSVaclav Hapla   PetscFunctionReturn(0);
51040c0a32dcSVaclav Hapla }
51050c0a32dcSVaclav Hapla 
51060c0a32dcSVaclav Hapla /*@
5107ba2698f1SMatthew G. Knepley   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
5108ba2698f1SMatthew G. Knepley 
5109ba2698f1SMatthew G. Knepley   Not Collective
5110ba2698f1SMatthew G. Knepley 
5111ba2698f1SMatthew G. Knepley   Input Parameter:
5112ba2698f1SMatthew G. Knepley . dm - The DMPlex object
5113ba2698f1SMatthew G. Knepley 
5114ba2698f1SMatthew G. Knepley   Output Parameter:
5115ba2698f1SMatthew G. Knepley . celltypeLabel - The DMLabel recording cell polytope type
5116ba2698f1SMatthew G. Knepley 
5117412e9a14SMatthew G. Knepley   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
5118412e9a14SMatthew G. Knepley   DMCreateLabel(dm, "celltype") beforehand.
5119412e9a14SMatthew G. Knepley 
5120ba2698f1SMatthew G. Knepley   Level: developer
5121ba2698f1SMatthew G. Knepley 
5122db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5123ba2698f1SMatthew G. Knepley @*/
5124d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5125d71ae5a4SJacob Faibussowitsch {
5126ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5127ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5128ba2698f1SMatthew G. Knepley   PetscValidPointer(celltypeLabel, 2);
51299566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5130ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
5131ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
5132ba2698f1SMatthew G. Knepley }
5133ba2698f1SMatthew G. Knepley 
5134ba2698f1SMatthew G. Knepley /*@
5135ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5136ba2698f1SMatthew G. Knepley 
5137ba2698f1SMatthew G. Knepley   Not Collective
5138ba2698f1SMatthew G. Knepley 
5139d8d19677SJose E. Roman   Input Parameters:
5140ba2698f1SMatthew G. Knepley + dm   - The DMPlex object
5141ba2698f1SMatthew G. Knepley - cell - The cell
5142ba2698f1SMatthew G. Knepley 
5143ba2698f1SMatthew G. Knepley   Output Parameter:
5144ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5145ba2698f1SMatthew G. Knepley 
5146ba2698f1SMatthew G. Knepley   Level: intermediate
5147ba2698f1SMatthew G. Knepley 
5148db781477SPatrick Sanan .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5149ba2698f1SMatthew G. Knepley @*/
5150d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5151d71ae5a4SJacob Faibussowitsch {
5152*9f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5153ba2698f1SMatthew G. Knepley   DMLabel  label;
5154ba2698f1SMatthew G. Knepley   PetscInt ct;
5155ba2698f1SMatthew G. Knepley 
5156ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5157ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5158ba2698f1SMatthew G. Knepley   PetscValidPointer(celltype, 3);
5159*9f4ada15SMatthew G. Knepley   if (mesh->tr) {
5160*9f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
5161*9f4ada15SMatthew G. Knepley   } else {
51629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
51639566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, cell, &ct));
516463a3b9bcSJacob Faibussowitsch     PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5165ba2698f1SMatthew G. Knepley     *celltype = (DMPolytopeType)ct;
5166*9f4ada15SMatthew G. Knepley   }
5167ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
5168ba2698f1SMatthew G. Knepley }
5169ba2698f1SMatthew G. Knepley 
5170412e9a14SMatthew G. Knepley /*@
5171412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5172412e9a14SMatthew G. Knepley 
5173412e9a14SMatthew G. Knepley   Not Collective
5174412e9a14SMatthew G. Knepley 
5175412e9a14SMatthew G. Knepley   Input Parameters:
5176412e9a14SMatthew G. Knepley + dm   - The DMPlex object
5177412e9a14SMatthew G. Knepley . cell - The cell
5178412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5179412e9a14SMatthew G. Knepley 
5180412e9a14SMatthew G. Knepley   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
5181412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5182412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5183412e9a14SMatthew G. Knepley   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
5184412e9a14SMatthew G. Knepley 
5185412e9a14SMatthew G. Knepley   Level: advanced
5186412e9a14SMatthew G. Knepley 
5187db781477SPatrick Sanan .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5188412e9a14SMatthew G. Knepley @*/
5189d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5190d71ae5a4SJacob Faibussowitsch {
5191412e9a14SMatthew G. Knepley   DMLabel label;
5192412e9a14SMatthew G. Knepley 
5193412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5194412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
51969566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
5197412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
5198412e9a14SMatthew G. Knepley }
5199412e9a14SMatthew G. Knepley 
5200d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5201d71ae5a4SJacob Faibussowitsch {
5202efe440bfSMatthew G. Knepley   PetscSection section, s;
5203efe440bfSMatthew G. Knepley   Mat          m;
52043e922f36SToby Isaac   PetscInt     maxHeight;
5205552f7358SJed Brown 
5206552f7358SJed Brown   PetscFunctionBegin;
52079566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
52089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
52099566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
52109566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
52119566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
52129566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
52139566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
52149566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
52159566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
52169566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&s));
52179566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&m));
52188f4c458bSMatthew G. Knepley 
52199566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
52209566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5221552f7358SJed Brown   PetscFunctionReturn(0);
5222552f7358SJed Brown }
5223552f7358SJed Brown 
5224d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5225d71ae5a4SJacob Faibussowitsch {
52266858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
52276858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5228f19dbd58SToby Isaac 
5229f19dbd58SToby Isaac   PetscFunctionBegin;
5230f19dbd58SToby Isaac   *field = NULL;
52319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
52329566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
52336858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
52346858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5235f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
52366858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
52376858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5238f19dbd58SToby Isaac   }
5239f19dbd58SToby Isaac   PetscFunctionReturn(0);
5240f19dbd58SToby Isaac }
5241f19dbd58SToby Isaac 
52427cd05799SMatthew G. Knepley /*@C
52437cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
52447cd05799SMatthew G. Knepley 
52457cd05799SMatthew G. Knepley   Not Collective
52467cd05799SMatthew G. Knepley 
52477cd05799SMatthew G. Knepley   Input Parameters:
52487cd05799SMatthew G. Knepley . dm        - The DMPlex object
52497cd05799SMatthew G. Knepley 
52507cd05799SMatthew G. Knepley   Output Parameter:
52517cd05799SMatthew G. Knepley . section - The PetscSection object
52527cd05799SMatthew G. Knepley 
52537cd05799SMatthew G. Knepley   Level: developer
52547cd05799SMatthew G. Knepley 
5255db781477SPatrick Sanan .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`
52567cd05799SMatthew G. Knepley @*/
5257d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5258d71ae5a4SJacob Faibussowitsch {
5259552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5260552f7358SJed Brown 
5261552f7358SJed Brown   PetscFunctionBegin;
5262552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5263552f7358SJed Brown   if (section) *section = mesh->coneSection;
5264552f7358SJed Brown   PetscFunctionReturn(0);
5265552f7358SJed Brown }
5266552f7358SJed Brown 
52677cd05799SMatthew G. Knepley /*@C
52687cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
52697cd05799SMatthew G. Knepley 
52707cd05799SMatthew G. Knepley   Not Collective
52717cd05799SMatthew G. Knepley 
52727cd05799SMatthew G. Knepley   Input Parameters:
52737cd05799SMatthew G. Knepley . dm        - The DMPlex object
52747cd05799SMatthew G. Knepley 
52757cd05799SMatthew G. Knepley   Output Parameter:
52767cd05799SMatthew G. Knepley . section - The PetscSection object
52777cd05799SMatthew G. Knepley 
52787cd05799SMatthew G. Knepley   Level: developer
52797cd05799SMatthew G. Knepley 
5280db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`
52817cd05799SMatthew G. Knepley @*/
5282d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5283d71ae5a4SJacob Faibussowitsch {
52848cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
52858cb4d582SMatthew G. Knepley 
52868cb4d582SMatthew G. Knepley   PetscFunctionBegin;
52878cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
52888cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
52898cb4d582SMatthew G. Knepley   PetscFunctionReturn(0);
52908cb4d582SMatthew G. Knepley }
52918cb4d582SMatthew G. Knepley 
52927cd05799SMatthew G. Knepley /*@C
52937cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
52947cd05799SMatthew G. Knepley 
52957cd05799SMatthew G. Knepley   Not Collective
52967cd05799SMatthew G. Knepley 
52977cd05799SMatthew G. Knepley   Input Parameters:
52987cd05799SMatthew G. Knepley . dm        - The DMPlex object
52997cd05799SMatthew G. Knepley 
53007cd05799SMatthew G. Knepley   Output Parameter:
53017cd05799SMatthew G. Knepley . cones - The cone for each point
53027cd05799SMatthew G. Knepley 
53037cd05799SMatthew G. Knepley   Level: developer
53047cd05799SMatthew G. Knepley 
5305db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`
53067cd05799SMatthew G. Knepley @*/
5307d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5308d71ae5a4SJacob Faibussowitsch {
5309552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5310552f7358SJed Brown 
5311552f7358SJed Brown   PetscFunctionBegin;
5312552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5313552f7358SJed Brown   if (cones) *cones = mesh->cones;
5314552f7358SJed Brown   PetscFunctionReturn(0);
5315552f7358SJed Brown }
5316552f7358SJed Brown 
53177cd05799SMatthew G. Knepley /*@C
53187cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
53197cd05799SMatthew G. Knepley 
53207cd05799SMatthew G. Knepley   Not Collective
53217cd05799SMatthew G. Knepley 
53227cd05799SMatthew G. Knepley   Input Parameters:
53237cd05799SMatthew G. Knepley . dm        - The DMPlex object
53247cd05799SMatthew G. Knepley 
53257cd05799SMatthew G. Knepley   Output Parameter:
5326b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
53277cd05799SMatthew G. Knepley 
53287cd05799SMatthew G. Knepley   Level: developer
53297cd05799SMatthew G. Knepley 
5330b5a892a1SMatthew G. Knepley   Notes:
5331b5a892a1SMatthew G. Knepley   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5332b5a892a1SMatthew G. Knepley 
5333b5a892a1SMatthew G. Knepley   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5334b5a892a1SMatthew G. Knepley 
5335db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`
53367cd05799SMatthew G. Knepley @*/
5337d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5338d71ae5a4SJacob Faibussowitsch {
5339552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5340552f7358SJed Brown 
5341552f7358SJed Brown   PetscFunctionBegin;
5342552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5343552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5344552f7358SJed Brown   PetscFunctionReturn(0);
5345552f7358SJed Brown }
5346552f7358SJed Brown 
5347552f7358SJed Brown /******************************** FEM Support **********************************/
5348552f7358SJed Brown 
53499e8305c2SJed Brown /*
53509e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
53519e8305c2SJed Brown  representing a line in the section.
53529e8305c2SJed Brown */
5353d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k)
5354d71ae5a4SJacob Faibussowitsch {
53559e8305c2SJed Brown   PetscFunctionBeginHot;
53569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5357a433471fSStefano Zampini   if (line < 0) {
5358a433471fSStefano Zampini     *k  = 0;
5359a433471fSStefano Zampini     *Nc = 0;
5360a433471fSStefano Zampini   } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */
53619e8305c2SJed Brown     *k = 1;
53629e8305c2SJed Brown   } else { /* Assume the full interpolated mesh is in the chart; lines in particular */
53639e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
53649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
53659e8305c2SJed Brown     *k = *k / *Nc + 1;
53669e8305c2SJed Brown   }
53679e8305c2SJed Brown   PetscFunctionReturn(0);
53689e8305c2SJed Brown }
53699e8305c2SJed Brown 
5370a4355906SMatthew Knepley /*@
5371bc1eb3faSJed Brown 
5372bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5373bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
53741bb6d2a8SBarry Smith   section provided (or the section of the DM).
5375a4355906SMatthew Knepley 
5376a4355906SMatthew Knepley   Input Parameters:
5377a4355906SMatthew Knepley + dm      - The DM
5378a4355906SMatthew Knepley . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5379a4355906SMatthew Knepley - section - The PetscSection to reorder, or NULL for the default section
5380a4355906SMatthew Knepley 
5381a4355906SMatthew Knepley   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5382a4355906SMatthew Knepley   degree of the basis.
5383a4355906SMatthew Knepley 
5384bc1eb3faSJed Brown   Example:
5385bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5386bc1eb3faSJed Brown .vb
5387bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5388bc1eb3faSJed Brown 
5389bc1eb3faSJed Brown   v4 -- e6 -- v3
5390bc1eb3faSJed Brown   |           |
5391bc1eb3faSJed Brown   e7    c0    e8
5392bc1eb3faSJed Brown   |           |
5393bc1eb3faSJed Brown   v1 -- e5 -- v2
5394bc1eb3faSJed Brown .ve
5395bc1eb3faSJed Brown 
5396bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5397bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5398bc1eb3faSJed Brown .vb
5399bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5400bc1eb3faSJed Brown     v1 -> [4]
5401bc1eb3faSJed Brown     ...
5402bc1eb3faSJed Brown     e5 -> [8, 9]
5403bc1eb3faSJed Brown .ve
5404bc1eb3faSJed Brown 
5405bc1eb3faSJed Brown   which corresponds to the dofs
5406bc1eb3faSJed Brown .vb
5407bc1eb3faSJed Brown     6   10  11  7
5408bc1eb3faSJed Brown     13  2   3   15
5409bc1eb3faSJed Brown     12  0   1   14
5410bc1eb3faSJed Brown     4   8   9   5
5411bc1eb3faSJed Brown .ve
5412bc1eb3faSJed Brown 
5413bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5414bc1eb3faSJed Brown .vb
5415bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5416bc1eb3faSJed Brown .ve
5417bc1eb3faSJed Brown 
5418bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5419bc1eb3faSJed Brown .vb
5420bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5421bc1eb3faSJed Brown .ve
5422bc1eb3faSJed Brown 
5423a4355906SMatthew Knepley   Level: developer
5424a4355906SMatthew Knepley 
5425db781477SPatrick Sanan .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5426a4355906SMatthew Knepley @*/
5427d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5428d71ae5a4SJacob Faibussowitsch {
54297391a63aSMatthew G. Knepley   DMLabel   label;
5430bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
54319e8305c2SJed Brown   PetscBool vertexchart;
54323194fc30SMatthew G. Knepley 
54333194fc30SMatthew G. Knepley   PetscFunctionBegin;
54349566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
5435a433471fSStefano Zampini   if (dim < 1) PetscFunctionReturn(0);
5436a433471fSStefano Zampini   if (point < 0) {
5437a433471fSStefano Zampini     PetscInt sStart, sEnd;
5438a433471fSStefano Zampini 
54399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5440a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
5441a433471fSStefano Zampini   }
54429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
54439566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
54449566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
54459371c9d4SSatish Balay   if (depth == 1) {
54469371c9d4SSatish Balay     eStart = point;
54479371c9d4SSatish Balay   } else if (depth == dim) {
54487391a63aSMatthew G. Knepley     const PetscInt *cone;
54497391a63aSMatthew G. Knepley 
54509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5451d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5452d4e6627bSStefano Zampini     else if (dim == 3) {
5453d4e6627bSStefano Zampini       const PetscInt *cone2;
54549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5455d4e6627bSStefano Zampini       eStart = cone2[0];
545663a3b9bcSJacob 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);
545763a3b9bcSJacob 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);
54589e8305c2SJed Brown   { /* Determine whether the chart covers all points or just vertices. */
54599e8305c2SJed Brown     PetscInt pStart, pEnd, cStart, cEnd;
54609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd));
54619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section, &cStart, &cEnd));
5462796d0a68SJed Brown     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5463796d0a68SJed Brown     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5464796d0a68SJed Brown     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
54659e8305c2SJed Brown   }
54669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5467bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
5468bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5469bb197d40SJed Brown     PetscInt *perm;
5470bb197d40SJed Brown 
54713194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
54729566063dSJacob Faibussowitsch       PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5473bb197d40SJed Brown       size += PetscPowInt(k + 1, d) * Nc;
54743194fc30SMatthew G. Knepley     }
54759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
54763194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5477bb197d40SJed Brown       switch (d) {
5478babf31e0SJed Brown       case 1:
54799566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5480babf31e0SJed Brown         /*
5481babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5482babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5483babf31e0SJed Brown          */
5484babf31e0SJed Brown         for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
54859371c9d4SSatish Balay         for (i = 0; i < k - 1; i++)
54869371c9d4SSatish Balay           for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5487babf31e0SJed Brown         for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5488babf31e0SJed Brown         foffset = offset;
5489babf31e0SJed Brown         break;
549089eabcffSMatthew G. Knepley       case 2:
54913194fc30SMatthew 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} */
54929566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
54933194fc30SMatthew G. Knepley         /* The SEM order is
54943194fc30SMatthew G. Knepley 
54953194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
549689eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
54973194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
54983194fc30SMatthew G. Knepley          */
54993194fc30SMatthew G. Knepley         {
55003194fc30SMatthew G. Knepley           const PetscInt of   = 0;
55013194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
55023194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
55033194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
55043194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
55053194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
55063194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
55073194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
55083194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
55093194fc30SMatthew G. Knepley           PetscInt       o;
55103194fc30SMatthew G. Knepley 
55113194fc30SMatthew G. Knepley           /* bottom */
55123194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
55139371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
55149371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
55153194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
55163194fc30SMatthew G. Knepley           /* middle */
55173194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
55183194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
55199371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
55209371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
55213194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
55223194fc30SMatthew G. Knepley           }
55233194fc30SMatthew G. Knepley           /* top */
55243194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
55259371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
55269371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
55273194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
55283194fc30SMatthew G. Knepley           foffset = offset;
55293194fc30SMatthew G. Knepley         }
553089eabcffSMatthew G. Knepley         break;
553189eabcffSMatthew G. Knepley       case 3:
553289eabcffSMatthew G. Knepley         /* The original hex closure is
553389eabcffSMatthew G. Knepley 
553489eabcffSMatthew G. Knepley          {c,
553589eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
553689eabcffSMatthew 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,
553789eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
553889eabcffSMatthew G. Knepley          */
55399566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
554089eabcffSMatthew G. Knepley         /* The SEM order is
554189eabcffSMatthew G. Knepley          Bottom Slice
554289eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
554389eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
554489eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
554589eabcffSMatthew G. Knepley 
554689eabcffSMatthew G. Knepley          Middle Slice (j)
554789eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
554889eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
554989eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
555089eabcffSMatthew G. Knepley 
555189eabcffSMatthew G. Knepley          Top Slice
555289eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
555389eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
555489eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
555589eabcffSMatthew G. Knepley          */
555689eabcffSMatthew G. Knepley         {
555789eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
555889eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
555989eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
556089eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
556189eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
556289eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
556389eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
556489eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
556589eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
556689eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
556789eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
556889eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
556989eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
557089eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
557189eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
557289eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
557389eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
557489eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
557589eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
557689eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
557789eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
557889eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
557989eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
558089eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
558189eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
558289eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
558389eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
558489eabcffSMatthew G. Knepley           PetscInt       o, n;
558589eabcffSMatthew G. Knepley 
558689eabcffSMatthew G. Knepley           /* Bottom Slice */
558789eabcffSMatthew G. Knepley           /*   bottom */
558889eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
55899371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
55909371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
559189eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
559289eabcffSMatthew G. Knepley           /*   middle */
559389eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
559489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
55959371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
55969371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
55979371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
55989371c9d4SSatish Balay             }
559989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
56003194fc30SMatthew G. Knepley           }
560189eabcffSMatthew G. Knepley           /*   top */
560289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
56039371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
56049371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
560589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
560689eabcffSMatthew G. Knepley 
560789eabcffSMatthew G. Knepley           /* Middle Slice */
560889eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
560989eabcffSMatthew G. Knepley             /*   bottom */
561089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
56119371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
56129371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
561389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
561489eabcffSMatthew G. Knepley             /*   middle */
561589eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
561689eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
56179371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
56189371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
561989eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
562089eabcffSMatthew G. Knepley             }
562189eabcffSMatthew G. Knepley             /*   top */
562289eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
56239371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
56249371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
562589eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
562689eabcffSMatthew G. Knepley           }
562789eabcffSMatthew G. Knepley 
562889eabcffSMatthew G. Knepley           /* Top Slice */
562989eabcffSMatthew G. Knepley           /*   bottom */
563089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
56319371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
56329371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
563389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
563489eabcffSMatthew G. Knepley           /*   middle */
563589eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
563689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
56379371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
56389371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
563989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
564089eabcffSMatthew G. Knepley           }
564189eabcffSMatthew G. Knepley           /*   top */
564289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
56439371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
56449371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
564589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
564689eabcffSMatthew G. Knepley 
564789eabcffSMatthew G. Knepley           foffset = offset;
564889eabcffSMatthew G. Knepley         }
564989eabcffSMatthew G. Knepley         break;
5650d71ae5a4SJacob Faibussowitsch       default:
5651d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
565289eabcffSMatthew G. Knepley       }
565389eabcffSMatthew G. Knepley     }
565463a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
56553194fc30SMatthew G. Knepley     /* Check permutation */
56563194fc30SMatthew G. Knepley     {
56573194fc30SMatthew G. Knepley       PetscInt *check;
56583194fc30SMatthew G. Knepley 
56599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
56601dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
56611dca8a05SBarry Smith         check[i] = -1;
56621dca8a05SBarry 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]);
56631dca8a05SBarry Smith       }
56643194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
56651dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
56669566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
56673194fc30SMatthew G. Knepley     }
56689566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
5669a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5670a05c9aa3SJed Brown       PetscInt *loc_perm;
56719566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
5672a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
5673a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
5674a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
5675a05c9aa3SJed Brown       }
56769566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
5677a05c9aa3SJed Brown     }
5678bb197d40SJed Brown   }
56793194fc30SMatthew G. Knepley   PetscFunctionReturn(0);
56803194fc30SMatthew G. Knepley }
56813194fc30SMatthew G. Knepley 
5682d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5683d71ae5a4SJacob Faibussowitsch {
5684e071409bSToby Isaac   PetscDS  prob;
5685e071409bSToby Isaac   PetscInt depth, Nf, h;
5686e071409bSToby Isaac   DMLabel  label;
5687e071409bSToby Isaac 
5688e071409bSToby Isaac   PetscFunctionBeginHot;
56899566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
5690e071409bSToby Isaac   Nf      = prob->Nf;
5691e071409bSToby Isaac   label   = dm->depthLabel;
5692e071409bSToby Isaac   *dspace = NULL;
5693e071409bSToby Isaac   if (field < Nf) {
5694e071409bSToby Isaac     PetscObject disc = prob->disc[field];
5695e071409bSToby Isaac 
5696e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
5697e071409bSToby Isaac       PetscDualSpace dsp;
5698e071409bSToby Isaac 
56999566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
57009566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
57019566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
5702e071409bSToby Isaac       h = depth - 1 - h;
5703e071409bSToby Isaac       if (h) {
57049566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
5705e071409bSToby Isaac       } else {
5706e071409bSToby Isaac         *dspace = dsp;
5707e071409bSToby Isaac       }
5708e071409bSToby Isaac     }
5709e071409bSToby Isaac   }
5710e071409bSToby Isaac   PetscFunctionReturn(0);
5711e071409bSToby Isaac }
5712e071409bSToby Isaac 
5713d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5714d71ae5a4SJacob Faibussowitsch {
571528351e22SJed Brown   PetscScalar       *array;
571628351e22SJed Brown   const PetscScalar *vArray;
5717d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
57181a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
5719552f7358SJed Brown 
57201b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
57219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
57229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
57239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
57249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
57253f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
57269df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
57279df71ca4SMatthew G. Knepley       PetscInt dof;
5728d9917b9dSMatthew G. Knepley 
57299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
57309df71ca4SMatthew G. Knepley       size += dof;
57319df71ca4SMatthew G. Knepley     }
57329df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
57339df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
57342a3aaacfSMatthew G. Knepley       PetscInt       dof;
57355a1bb5cfSMatthew G. Knepley 
57365a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
57379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
57385a1bb5cfSMatthew G. Knepley       size += dof;
57395a1bb5cfSMatthew G. Knepley     }
57403f7cbbe7SMatthew G. Knepley     if (!values) {
57413f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
57423f7cbbe7SMatthew G. Knepley       PetscFunctionReturn(0);
57433f7cbbe7SMatthew G. Knepley     }
57449566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5745982e9ed1SMatthew G. Knepley   } else {
5746982e9ed1SMatthew G. Knepley     array = *values;
5747982e9ed1SMatthew G. Knepley   }
57489df71ca4SMatthew G. Knepley   size = 0;
574928351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
57509df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
57519df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
575228351e22SJed Brown     const PetscScalar *varr;
5753d9917b9dSMatthew G. Knepley 
57549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
57559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
57569df71ca4SMatthew G. Knepley     varr = &vArray[off];
5757ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
57589df71ca4SMatthew G. Knepley     size += dof;
57599df71ca4SMatthew G. Knepley   }
57609df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
57619df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
57629df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
57635a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
576428351e22SJed Brown     const PetscScalar *varr;
57655a1bb5cfSMatthew G. Knepley 
576652ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
57679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
57689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
57695a1bb5cfSMatthew G. Knepley     varr = &vArray[off];
57705a1bb5cfSMatthew G. Knepley     if (o >= 0) {
5771ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
57725a1bb5cfSMatthew G. Knepley     } else {
5773ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
57745a1bb5cfSMatthew G. Knepley     }
57759df71ca4SMatthew G. Knepley     size += dof;
57765a1bb5cfSMatthew G. Knepley   }
577728351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
57789df71ca4SMatthew G. Knepley   if (!*values) {
57795a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
57805a1bb5cfSMatthew G. Knepley     *values = array;
57819df71ca4SMatthew G. Knepley   } else {
578263a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
57838c312ff3SMatthew G. Knepley     *csize = size;
57849df71ca4SMatthew G. Knepley   }
57855a1bb5cfSMatthew G. Knepley   PetscFunctionReturn(0);
57865a1bb5cfSMatthew G. Knepley }
5787d9917b9dSMatthew G. Knepley 
578827f02ce8SMatthew G. Knepley /* Compress out points not in the section */
5789d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5790d71ae5a4SJacob Faibussowitsch {
579127f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
579227f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
579327f02ce8SMatthew G. Knepley 
57949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
579527f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
579627f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
579727f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
579827f02ce8SMatthew G. Knepley       points[q * 2]     = r;
579927f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
580027f02ce8SMatthew G. Knepley       ++q;
580127f02ce8SMatthew G. Knepley     }
580227f02ce8SMatthew G. Knepley   }
580327f02ce8SMatthew G. Knepley   *numPoints = q;
580427f02ce8SMatthew G. Knepley   return 0;
580527f02ce8SMatthew G. Knepley }
580627f02ce8SMatthew G. Knepley 
580797529cf3SJed Brown /* Compressed closure does not apply closure permutation */
5808d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5809d71ae5a4SJacob Faibussowitsch {
581027f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
5811923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
5812923c78e0SToby Isaac 
5813923c78e0SToby Isaac   PetscFunctionBeginHot;
58149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
581527f02ce8SMatthew G. Knepley   if (*clPoints) {
5816923c78e0SToby Isaac     PetscInt dof, off;
5817923c78e0SToby Isaac 
58189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
58199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
58209566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
5821923c78e0SToby Isaac     np  = dof / 2;
5822923c78e0SToby Isaac     pts = (PetscInt *)&cla[off];
582327f02ce8SMatthew G. Knepley   } else {
58249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts));
58259566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
5826923c78e0SToby Isaac   }
5827923c78e0SToby Isaac   *numPoints = np;
5828923c78e0SToby Isaac   *points    = pts;
5829923c78e0SToby Isaac   *clp       = cla;
5830923c78e0SToby Isaac   PetscFunctionReturn(0);
5831923c78e0SToby Isaac }
5832923c78e0SToby Isaac 
5833d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5834d71ae5a4SJacob Faibussowitsch {
5835923c78e0SToby Isaac   PetscFunctionBeginHot;
5836923c78e0SToby Isaac   if (!*clPoints) {
58379566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5838923c78e0SToby Isaac   } else {
58399566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
5840923c78e0SToby Isaac   }
5841923c78e0SToby Isaac   *numPoints = 0;
5842923c78e0SToby Isaac   *points    = NULL;
5843923c78e0SToby Isaac   *clSec     = NULL;
5844923c78e0SToby Isaac   *clPoints  = NULL;
5845923c78e0SToby Isaac   *clp       = NULL;
5846923c78e0SToby Isaac   PetscFunctionReturn(0);
5847923c78e0SToby Isaac }
5848923c78e0SToby Isaac 
5849d71ae5a4SJacob 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[])
5850d71ae5a4SJacob Faibussowitsch {
58511a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
585297e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
585397e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
58541a271a75SMatthew G. Knepley 
58551a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5856fe02ba77SJed Brown   *size = 0;
58579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
585897e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
585997e99dd9SToby Isaac     const PetscInt     point = points[2 * p];
586097e99dd9SToby Isaac     const PetscInt    *perm  = perms ? perms[p] : NULL;
586197e99dd9SToby Isaac     const PetscScalar *flip  = flips ? flips[p] : NULL;
58621a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
58631a271a75SMatthew G. Knepley     const PetscScalar *varr;
58641a271a75SMatthew G. Knepley 
58659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
58669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
58671a271a75SMatthew G. Knepley     varr = &vArray[off];
586897e99dd9SToby Isaac     if (clperm) {
586997e99dd9SToby Isaac       if (perm) {
587097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
58711a271a75SMatthew G. Knepley       } else {
587297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
587397e99dd9SToby Isaac       }
587497e99dd9SToby Isaac       if (flip) {
587597e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
587697e99dd9SToby Isaac       }
587797e99dd9SToby Isaac     } else {
587897e99dd9SToby Isaac       if (perm) {
587997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
588097e99dd9SToby Isaac       } else {
588197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
588297e99dd9SToby Isaac       }
588397e99dd9SToby Isaac       if (flip) {
588497e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
58851a271a75SMatthew G. Knepley       }
58861a271a75SMatthew G. Knepley     }
588797e99dd9SToby Isaac     offset += dof;
588897e99dd9SToby Isaac   }
58899566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
58901a271a75SMatthew G. Knepley   *size = offset;
58911a271a75SMatthew G. Knepley   PetscFunctionReturn(0);
58921a271a75SMatthew G. Knepley }
58931a271a75SMatthew G. Knepley 
5894d71ae5a4SJacob 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[])
5895d71ae5a4SJacob Faibussowitsch {
58961a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
58971a271a75SMatthew G. Knepley 
58981a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5899fe02ba77SJed Brown   *size = 0;
59001a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
590197e99dd9SToby Isaac     PetscInt            p;
590297e99dd9SToby Isaac     const PetscInt    **perms = NULL;
590397e99dd9SToby Isaac     const PetscScalar **flips = NULL;
59041a271a75SMatthew G. Knepley 
59059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
590697e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
590797e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
590897e99dd9SToby Isaac       PetscInt           fdof, foff, b;
59091a271a75SMatthew G. Knepley       const PetscScalar *varr;
591097e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
591197e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
59121a271a75SMatthew G. Knepley 
59139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
59149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
59151a271a75SMatthew G. Knepley       varr = &vArray[foff];
591697e99dd9SToby Isaac       if (clperm) {
59179371c9d4SSatish Balay         if (perm) {
5918ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
59191a271a75SMatthew G. Knepley         } else {
5920ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
59219371c9d4SSatish Balay         }
59229371c9d4SSatish Balay         if (flip) {
5923ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
59249371c9d4SSatish Balay         }
59259371c9d4SSatish Balay       } else {
59269371c9d4SSatish Balay         if (perm) {
5927ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
59289371c9d4SSatish Balay         } else {
5929ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
59309371c9d4SSatish Balay         }
59319371c9d4SSatish Balay         if (flip) {
5932ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
59339371c9d4SSatish Balay         }
59341a271a75SMatthew G. Knepley       }
593597e99dd9SToby Isaac       offset += fdof;
59361a271a75SMatthew G. Knepley     }
59379566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
59381a271a75SMatthew G. Knepley   }
59391a271a75SMatthew G. Knepley   *size = offset;
59401a271a75SMatthew G. Knepley   PetscFunctionReturn(0);
59411a271a75SMatthew G. Knepley }
59421a271a75SMatthew G. Knepley 
5943552f7358SJed Brown /*@C
5944552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5945552f7358SJed Brown 
5946552f7358SJed Brown   Not collective
5947552f7358SJed Brown 
5948552f7358SJed Brown   Input Parameters:
5949552f7358SJed Brown + dm - The DM
5950552f7358SJed Brown . section - The section describing the layout in v, or NULL to use the default section
5951552f7358SJed Brown . v - The local vector
59526b867d5aSJose E. Roman - point - The point in the DM
5953552f7358SJed Brown 
59546b867d5aSJose E. Roman   Input/Output Parameters:
59556b867d5aSJose E. Roman + csize  - The size of the input values array, or NULL; on output the number of values in the closure
59566b867d5aSJose E. Roman - values - An array to use for the values, or NULL to have it allocated automatically;
59576b867d5aSJose E. Roman            if the user provided NULL, it is a borrowed array and should not be freed
595822c1ee49SMatthew G. Knepley 
595922c1ee49SMatthew G. Knepley $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
596022c1ee49SMatthew G. Knepley $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
596122c1ee49SMatthew G. Knepley $ assembly function, and a user may already have allocated storage for this operation.
596222c1ee49SMatthew G. Knepley $
596322c1ee49SMatthew G. Knepley $ A typical use could be
596422c1ee49SMatthew G. Knepley $
596522c1ee49SMatthew G. Knepley $  values = NULL;
59669566063dSJacob Faibussowitsch $  PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
596722c1ee49SMatthew G. Knepley $  for (cl = 0; cl < clSize; ++cl) {
596822c1ee49SMatthew G. Knepley $    <Compute on closure>
596922c1ee49SMatthew G. Knepley $  }
59709566063dSJacob Faibussowitsch $  PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
597122c1ee49SMatthew G. Knepley $
597222c1ee49SMatthew G. Knepley $ or
597322c1ee49SMatthew G. Knepley $
597422c1ee49SMatthew G. Knepley $  PetscMalloc1(clMaxSize, &values);
597522c1ee49SMatthew G. Knepley $  for (p = pStart; p < pEnd; ++p) {
597622c1ee49SMatthew G. Knepley $    clSize = clMaxSize;
59779566063dSJacob Faibussowitsch $    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
597822c1ee49SMatthew G. Knepley $    for (cl = 0; cl < clSize; ++cl) {
597922c1ee49SMatthew G. Knepley $      <Compute on closure>
598022c1ee49SMatthew G. Knepley $    }
598122c1ee49SMatthew G. Knepley $  }
598222c1ee49SMatthew G. Knepley $  PetscFree(values);
5983552f7358SJed Brown 
5984552f7358SJed Brown   Fortran Notes:
5985552f7358SJed Brown   Since it returns an array, this routine is only available in Fortran 90, and you must
5986552f7358SJed Brown   include petsc.h90 in your code.
5987552f7358SJed Brown 
5988552f7358SJed Brown   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5989552f7358SJed Brown 
5990552f7358SJed Brown   Level: intermediate
5991552f7358SJed Brown 
5992db781477SPatrick Sanan .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
5993552f7358SJed Brown @*/
5994d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5995d71ae5a4SJacob Faibussowitsch {
5996552f7358SJed Brown   PetscSection    clSection;
5997d9917b9dSMatthew G. Knepley   IS              clPoints;
5998552f7358SJed Brown   PetscInt       *points = NULL;
5999c459fbc1SJed Brown   const PetscInt *clp, *perm;
6000c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, asize;
6001552f7358SJed Brown 
6002d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
6003552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
60049566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
60051a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
60061a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
60079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
60089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6009552f7358SJed Brown   if (depth == 1 && numFields < 2) {
60109566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6011552f7358SJed Brown     PetscFunctionReturn(0);
6012552f7358SJed Brown   }
60131a271a75SMatthew G. Knepley   /* Get points */
60149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6015c459fbc1SJed Brown   /* Get sizes */
6016c459fbc1SJed Brown   asize = 0;
6017c459fbc1SJed Brown   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
6018c459fbc1SJed Brown     PetscInt dof;
60199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
60201a271a75SMatthew G. Knepley     asize += dof;
6021552f7358SJed Brown   }
6022c459fbc1SJed Brown   if (values) {
6023c459fbc1SJed Brown     const PetscScalar *vArray;
6024c459fbc1SJed Brown     PetscInt           size;
6025c459fbc1SJed Brown 
6026c459fbc1SJed Brown     if (*values) {
602763a3b9bcSJacob Faibussowitsch       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);
60289566063dSJacob Faibussowitsch     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
60299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
60309566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, &vArray));
60311a271a75SMatthew G. Knepley     /* Get values */
60329566063dSJacob Faibussowitsch     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
60339566063dSJacob Faibussowitsch     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
603463a3b9bcSJacob Faibussowitsch     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
60351a271a75SMatthew G. Knepley     /* Cleanup array */
60369566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, &vArray));
6037d0f6b257SMatthew G. Knepley   }
6038c459fbc1SJed Brown   if (csize) *csize = asize;
6039c459fbc1SJed Brown   /* Cleanup points */
60409566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6041552f7358SJed Brown   PetscFunctionReturn(0);
6042552f7358SJed Brown }
6043552f7358SJed Brown 
6044d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6045d71ae5a4SJacob Faibussowitsch {
6046e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6047e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6048e5c487bfSMatthew G. Knepley   IS                 clPoints;
6049e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6050e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6051e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6052c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6053c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6054e5c487bfSMatthew G. Knepley 
6055e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6056e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
60579566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6058e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6059e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
60609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
60619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
60629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6063e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
60649566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6065e5c487bfSMatthew G. Knepley     PetscFunctionReturn(0);
6066e5c487bfSMatthew G. Knepley   }
6067e5c487bfSMatthew G. Knepley   /* Get points */
60689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6069c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6070c459fbc1SJed Brown     PetscInt dof;
60719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6072c459fbc1SJed Brown     clsize += dof;
6073c459fbc1SJed Brown   }
60749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6075e5c487bfSMatthew G. Knepley   /* Filter points */
6076e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6077e5c487bfSMatthew G. Knepley     PetscInt dep;
6078e5c487bfSMatthew G. Knepley 
60799566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6080e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6081e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6082e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6083e5c487bfSMatthew G. Knepley     ++Np;
6084e5c487bfSMatthew G. Knepley   }
6085e5c487bfSMatthew G. Knepley   /* Get array */
6086e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6087e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6088e5c487bfSMatthew G. Knepley 
6089e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
60909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6091e5c487bfSMatthew G. Knepley       asize += dof;
6092e5c487bfSMatthew G. Knepley     }
6093e5c487bfSMatthew G. Knepley     if (!values) {
60949566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6095e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
6096e5c487bfSMatthew G. Knepley       PetscFunctionReturn(0);
6097e5c487bfSMatthew G. Knepley     }
60989566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6099e5c487bfSMatthew G. Knepley   } else {
6100e5c487bfSMatthew G. Knepley     array = *values;
6101e5c487bfSMatthew G. Knepley   }
61029566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6103e5c487bfSMatthew G. Knepley   /* Get values */
61049566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
61059566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6106e5c487bfSMatthew G. Knepley   /* Cleanup points */
61079566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6108e5c487bfSMatthew G. Knepley   /* Cleanup array */
61099566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6110e5c487bfSMatthew G. Knepley   if (!*values) {
6111e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6112e5c487bfSMatthew G. Knepley     *values = array;
6113e5c487bfSMatthew G. Knepley   } else {
611463a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6115e5c487bfSMatthew G. Knepley     *csize = size;
6116e5c487bfSMatthew G. Knepley   }
6117e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
6118e5c487bfSMatthew G. Knepley }
6119e5c487bfSMatthew G. Knepley 
6120552f7358SJed Brown /*@C
6121552f7358SJed Brown   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6122552f7358SJed Brown 
6123552f7358SJed Brown   Not collective
6124552f7358SJed Brown 
6125552f7358SJed Brown   Input Parameters:
6126552f7358SJed Brown + dm - The DM
61270298fd71SBarry Smith . section - The section describing the layout in v, or NULL to use the default section
6128552f7358SJed Brown . v - The local vector
6129eaf898f9SPatrick Sanan . point - The point in the DM
61300298fd71SBarry Smith . csize - The number of values in the closure, or NULL
6131552f7358SJed Brown - values - The array of values, which is a borrowed array and should not be freed
6132552f7358SJed Brown 
613322c1ee49SMatthew G. Knepley   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
613422c1ee49SMatthew G. Knepley 
61353813dfbdSMatthew G Knepley   Fortran Notes:
61363813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
61373813dfbdSMatthew G Knepley   include petsc.h90 in your code.
61383813dfbdSMatthew G Knepley 
61393813dfbdSMatthew G Knepley   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
61403813dfbdSMatthew G Knepley 
6141552f7358SJed Brown   Level: intermediate
6142552f7358SJed Brown 
6143db781477SPatrick Sanan .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6144552f7358SJed Brown @*/
6145d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6146d71ae5a4SJacob Faibussowitsch {
6147552f7358SJed Brown   PetscInt size = 0;
6148552f7358SJed Brown 
6149552f7358SJed Brown   PetscFunctionBegin;
6150552f7358SJed Brown   /* Should work without recalculating size */
61519566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6152c9fdaa05SMatthew G. Knepley   *values = NULL;
6153552f7358SJed Brown   PetscFunctionReturn(0);
6154552f7358SJed Brown }
6155552f7358SJed Brown 
6156d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6157d71ae5a4SJacob Faibussowitsch {
61589371c9d4SSatish Balay   *x += y;
61599371c9d4SSatish Balay }
6160d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6161d71ae5a4SJacob Faibussowitsch {
61629371c9d4SSatish Balay   *x = y;
61639371c9d4SSatish Balay }
6164552f7358SJed Brown 
6165d71ae5a4SJacob 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[])
6166d71ae5a4SJacob Faibussowitsch {
6167552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6168552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6169552f7358SJed Brown   PetscScalar    *a;
6170552f7358SJed Brown   PetscInt        off, cind = 0, k;
6171552f7358SJed Brown 
6172552f7358SJed Brown   PetscFunctionBegin;
61739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
61749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6175552f7358SJed Brown   a = &array[off];
6176552f7358SJed Brown   if (!cdof || setBC) {
617797e99dd9SToby Isaac     if (clperm) {
61789371c9d4SSatish Balay       if (perm) {
6179ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6180552f7358SJed Brown       } else {
6181ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
61829371c9d4SSatish Balay       }
61839371c9d4SSatish Balay     } else {
61849371c9d4SSatish Balay       if (perm) {
6185ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
61869371c9d4SSatish Balay       } else {
6187ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
61889371c9d4SSatish Balay       }
6189552f7358SJed Brown     }
6190552f7358SJed Brown   } else {
61919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
619297e99dd9SToby Isaac     if (clperm) {
61939371c9d4SSatish Balay       if (perm) {
61949371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
61959371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
61969371c9d4SSatish Balay             ++cind;
61979371c9d4SSatish Balay             continue;
61989371c9d4SSatish Balay           }
619997e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6200552f7358SJed Brown         }
6201552f7358SJed Brown       } else {
6202552f7358SJed Brown         for (k = 0; k < dof; ++k) {
62039371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
62049371c9d4SSatish Balay             ++cind;
62059371c9d4SSatish Balay             continue;
62069371c9d4SSatish Balay           }
620797e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
620897e99dd9SToby Isaac         }
620997e99dd9SToby Isaac       }
621097e99dd9SToby Isaac     } else {
621197e99dd9SToby Isaac       if (perm) {
621297e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
62139371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
62149371c9d4SSatish Balay             ++cind;
62159371c9d4SSatish Balay             continue;
62169371c9d4SSatish Balay           }
621797e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
621897e99dd9SToby Isaac         }
621997e99dd9SToby Isaac       } else {
622097e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
62219371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
62229371c9d4SSatish Balay             ++cind;
62239371c9d4SSatish Balay             continue;
62249371c9d4SSatish Balay           }
622597e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
622697e99dd9SToby Isaac         }
6227552f7358SJed Brown       }
6228552f7358SJed Brown     }
6229552f7358SJed Brown   }
6230552f7358SJed Brown   PetscFunctionReturn(0);
6231552f7358SJed Brown }
6232552f7358SJed Brown 
6233d71ae5a4SJacob 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[])
6234d71ae5a4SJacob Faibussowitsch {
6235a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6236a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6237a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6238a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6239a5e93ea8SMatthew G. Knepley 
6240a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
62419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
62429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6243a5e93ea8SMatthew G. Knepley   a = &array[off];
6244a5e93ea8SMatthew G. Knepley   if (cdof) {
62459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
624697e99dd9SToby Isaac     if (clperm) {
624797e99dd9SToby Isaac       if (perm) {
6248a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6249a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
625097e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
625197e99dd9SToby Isaac             cind++;
6252a5e93ea8SMatthew G. Knepley           }
6253a5e93ea8SMatthew G. Knepley         }
6254a5e93ea8SMatthew G. Knepley       } else {
6255a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6256a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
625797e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
625897e99dd9SToby Isaac             cind++;
625997e99dd9SToby Isaac           }
626097e99dd9SToby Isaac         }
626197e99dd9SToby Isaac       }
626297e99dd9SToby Isaac     } else {
626397e99dd9SToby Isaac       if (perm) {
626497e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
626597e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
626697e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
626797e99dd9SToby Isaac             cind++;
626897e99dd9SToby Isaac           }
626997e99dd9SToby Isaac         }
627097e99dd9SToby Isaac       } else {
627197e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
627297e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
627397e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
627497e99dd9SToby Isaac             cind++;
627597e99dd9SToby Isaac           }
6276a5e93ea8SMatthew G. Knepley         }
6277a5e93ea8SMatthew G. Knepley       }
6278a5e93ea8SMatthew G. Knepley     }
6279a5e93ea8SMatthew G. Knepley   }
6280a5e93ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6281a5e93ea8SMatthew G. Knepley }
6282a5e93ea8SMatthew G. Knepley 
6283d71ae5a4SJacob 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[])
6284d71ae5a4SJacob Faibussowitsch {
6285552f7358SJed Brown   PetscScalar    *a;
62861a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
62871a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
628897e99dd9SToby Isaac   PetscInt        cind = 0, b;
6289552f7358SJed Brown 
6290552f7358SJed Brown   PetscFunctionBegin;
62919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
62929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
62939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
62941a271a75SMatthew G. Knepley   a = &array[foff];
6295552f7358SJed Brown   if (!fcdof || setBC) {
629697e99dd9SToby Isaac     if (clperm) {
62979371c9d4SSatish Balay       if (perm) {
6298ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6299552f7358SJed Brown       } else {
6300ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
63019371c9d4SSatish Balay       }
63029371c9d4SSatish Balay     } else {
63039371c9d4SSatish Balay       if (perm) {
6304ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
63059371c9d4SSatish Balay       } else {
6306ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
63079371c9d4SSatish Balay       }
6308552f7358SJed Brown     }
6309552f7358SJed Brown   } else {
63109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
631197e99dd9SToby Isaac     if (clperm) {
631297e99dd9SToby Isaac       if (perm) {
631397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
63149371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
63159371c9d4SSatish Balay             ++cind;
63169371c9d4SSatish Balay             continue;
63179371c9d4SSatish Balay           }
631897e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6319552f7358SJed Brown         }
6320552f7358SJed Brown       } else {
632197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
63229371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
63239371c9d4SSatish Balay             ++cind;
63249371c9d4SSatish Balay             continue;
63259371c9d4SSatish Balay           }
632697e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
632797e99dd9SToby Isaac         }
632897e99dd9SToby Isaac       }
632997e99dd9SToby Isaac     } else {
633097e99dd9SToby Isaac       if (perm) {
633197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
63329371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
63339371c9d4SSatish Balay             ++cind;
63349371c9d4SSatish Balay             continue;
63359371c9d4SSatish Balay           }
633697e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
633797e99dd9SToby Isaac         }
633897e99dd9SToby Isaac       } else {
633997e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
63409371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
63419371c9d4SSatish Balay             ++cind;
63429371c9d4SSatish Balay             continue;
63439371c9d4SSatish Balay           }
634497e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6345552f7358SJed Brown         }
6346552f7358SJed Brown       }
6347552f7358SJed Brown     }
6348552f7358SJed Brown   }
63491a271a75SMatthew G. Knepley   *offset += fdof;
6350552f7358SJed Brown   PetscFunctionReturn(0);
6351552f7358SJed Brown }
6352552f7358SJed Brown 
6353d71ae5a4SJacob 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[])
6354d71ae5a4SJacob Faibussowitsch {
6355a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
63561a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
63571a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
63585da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6359ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6360a5e93ea8SMatthew G. Knepley 
6361a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
63629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
63639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
63649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
63659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
63661a271a75SMatthew G. Knepley   a = &array[foff];
6367a5e93ea8SMatthew G. Knepley   if (fcdof) {
6368ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
63699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
637097e99dd9SToby Isaac     if (clperm) {
637197e99dd9SToby Isaac       if (perm) {
6372ba322698SMatthew G. Knepley         if (comps) {
6373ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6374ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
63759371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
63769371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
63779371c9d4SSatish Balay               ncSet = PETSC_TRUE;
63789371c9d4SSatish Balay             }
63799371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
63809371c9d4SSatish Balay               ++cind;
63819371c9d4SSatish Balay               fcSet = PETSC_TRUE;
63829371c9d4SSatish Balay             }
6383ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6384ba322698SMatthew G. Knepley           }
6385ba322698SMatthew G. Knepley         } else {
638697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
638797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
638897e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6389a5e93ea8SMatthew G. Knepley               ++cind;
6390a5e93ea8SMatthew G. Knepley             }
6391a5e93ea8SMatthew G. Knepley           }
6392ba322698SMatthew G. Knepley         }
6393ba322698SMatthew G. Knepley       } else {
6394ba322698SMatthew G. Knepley         if (comps) {
6395ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6396ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
63979371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
63989371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
63999371c9d4SSatish Balay               ncSet = PETSC_TRUE;
64009371c9d4SSatish Balay             }
64019371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
64029371c9d4SSatish Balay               ++cind;
64039371c9d4SSatish Balay               fcSet = PETSC_TRUE;
64049371c9d4SSatish Balay             }
6405ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6406ba322698SMatthew G. Knepley           }
6407a5e93ea8SMatthew G. Knepley         } else {
640897e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
640997e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
641097e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
641197e99dd9SToby Isaac               ++cind;
641297e99dd9SToby Isaac             }
641397e99dd9SToby Isaac           }
641497e99dd9SToby Isaac         }
6415ba322698SMatthew G. Knepley       }
641697e99dd9SToby Isaac     } else {
641797e99dd9SToby Isaac       if (perm) {
6418ba322698SMatthew G. Knepley         if (comps) {
6419ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6420ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
64219371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
64229371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
64239371c9d4SSatish Balay               ncSet = PETSC_TRUE;
64249371c9d4SSatish Balay             }
64259371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
64269371c9d4SSatish Balay               ++cind;
64279371c9d4SSatish Balay               fcSet = PETSC_TRUE;
64289371c9d4SSatish Balay             }
6429ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6430ba322698SMatthew G. Knepley           }
6431ba322698SMatthew G. Knepley         } else {
643297e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
643397e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
643497e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
643597e99dd9SToby Isaac               ++cind;
643697e99dd9SToby Isaac             }
643797e99dd9SToby Isaac           }
6438ba322698SMatthew G. Knepley         }
6439ba322698SMatthew G. Knepley       } else {
6440ba322698SMatthew G. Knepley         if (comps) {
6441ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6442ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
64439371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
64449371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
64459371c9d4SSatish Balay               ncSet = PETSC_TRUE;
64469371c9d4SSatish Balay             }
64479371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
64489371c9d4SSatish Balay               ++cind;
64499371c9d4SSatish Balay               fcSet = PETSC_TRUE;
64509371c9d4SSatish Balay             }
6451ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6452ba322698SMatthew G. Knepley           }
645397e99dd9SToby Isaac         } else {
645497e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
645597e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
645697e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6457a5e93ea8SMatthew G. Knepley               ++cind;
6458a5e93ea8SMatthew G. Knepley             }
6459a5e93ea8SMatthew G. Knepley           }
6460a5e93ea8SMatthew G. Knepley         }
6461a5e93ea8SMatthew G. Knepley       }
6462a5e93ea8SMatthew G. Knepley     }
6463ba322698SMatthew G. Knepley   }
64641a271a75SMatthew G. Knepley   *offset += fdof;
6465a5e93ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6466a5e93ea8SMatthew G. Knepley }
6467a5e93ea8SMatthew G. Knepley 
6468d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6469d71ae5a4SJacob Faibussowitsch {
6470552f7358SJed Brown   PetscScalar    *array;
64711b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
64721b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6473552f7358SJed Brown 
64741b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
64759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
64769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
64779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
64789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
64799566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6480b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6481b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
6482b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
6483b6ebb6e6SMatthew G. Knepley 
64849371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
64859371c9d4SSatish Balay       dof = 0;
64869371c9d4SSatish Balay       continue;
64879371c9d4SSatish Balay     }
64889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
6489b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
6490b6ebb6e6SMatthew G. Knepley     {
6491b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6492b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
6493b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
6494b6ebb6e6SMatthew G. Knepley 
64959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
64969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6497b6ebb6e6SMatthew G. Knepley       a = &array[coff];
6498b6ebb6e6SMatthew G. Knepley       if (!cdof) {
6499b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6500ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6501b6ebb6e6SMatthew G. Knepley         } else {
6502ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6503b6ebb6e6SMatthew G. Knepley         }
6504b6ebb6e6SMatthew G. Knepley       } else {
65059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6506b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6507b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
65089371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
65099371c9d4SSatish Balay               ++cind;
65109371c9d4SSatish Balay               continue;
65119371c9d4SSatish Balay             }
6512b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
6513b6ebb6e6SMatthew G. Knepley           }
6514b6ebb6e6SMatthew G. Knepley         } else {
6515b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
65169371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
65179371c9d4SSatish Balay               ++cind;
65189371c9d4SSatish Balay               continue;
65199371c9d4SSatish Balay             }
6520b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
6521b6ebb6e6SMatthew G. Knepley           }
6522b6ebb6e6SMatthew G. Knepley         }
6523b6ebb6e6SMatthew G. Knepley       }
6524b6ebb6e6SMatthew G. Knepley     }
6525b6ebb6e6SMatthew G. Knepley   }
65269566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6527b6ebb6e6SMatthew G. Knepley   PetscFunctionReturn(0);
6528b6ebb6e6SMatthew G. Knepley }
65291b406b76SMatthew G. Knepley 
65301b406b76SMatthew G. Knepley /*@C
65311b406b76SMatthew G. Knepley   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
65321b406b76SMatthew G. Knepley 
65331b406b76SMatthew G. Knepley   Not collective
65341b406b76SMatthew G. Knepley 
65351b406b76SMatthew G. Knepley   Input Parameters:
65361b406b76SMatthew G. Knepley + dm - The DM
65371b406b76SMatthew G. Knepley . section - The section describing the layout in v, or NULL to use the default section
65381b406b76SMatthew G. Knepley . v - The local vector
6539eaf898f9SPatrick Sanan . point - The point in the DM
65401b406b76SMatthew G. Knepley . values - The array of values
654122c1ee49SMatthew G. Knepley - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
654222c1ee49SMatthew G. Knepley          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
65431b406b76SMatthew G. Knepley 
65441b406b76SMatthew G. Knepley   Fortran Notes:
65451b406b76SMatthew G. Knepley   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
65461b406b76SMatthew G. Knepley 
65471b406b76SMatthew G. Knepley   Level: intermediate
65481b406b76SMatthew G. Knepley 
6549db781477SPatrick Sanan .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
65501b406b76SMatthew G. Knepley @*/
6551d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6552d71ae5a4SJacob Faibussowitsch {
65531b406b76SMatthew G. Knepley   PetscSection    clSection;
65541b406b76SMatthew G. Knepley   IS              clPoints;
65551b406b76SMatthew G. Knepley   PetscScalar    *array;
65561b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
655727f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
6558c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
65591b406b76SMatthew G. Knepley 
65601a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
65611b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
65629566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
65631a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
65641a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
65659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
65669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
65671b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
65689566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
65691b406b76SMatthew G. Knepley     PetscFunctionReturn(0);
65701b406b76SMatthew G. Knepley   }
65711a271a75SMatthew G. Knepley   /* Get points */
65729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6573c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
6574c459fbc1SJed Brown     PetscInt dof;
65759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6576c459fbc1SJed Brown     clsize += dof;
6577c459fbc1SJed Brown   }
65789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
65791a271a75SMatthew G. Knepley   /* Get array */
65809566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
65811a271a75SMatthew G. Knepley   /* Get values */
6582ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
658397e99dd9SToby Isaac     PetscInt offset = 0, f;
6584552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
658597e99dd9SToby Isaac       const PetscInt    **perms = NULL;
658697e99dd9SToby Isaac       const PetscScalar **flips = NULL;
658797e99dd9SToby Isaac 
65889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6589552f7358SJed Brown       switch (mode) {
6590552f7358SJed Brown       case INSERT_VALUES:
659197e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
659297e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
659397e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
659497e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
659597e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
65969371c9d4SSatish Balay         }
65979371c9d4SSatish Balay         break;
6598552f7358SJed Brown       case INSERT_ALL_VALUES:
659997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
660097e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
660197e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
660297e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
660397e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
66049371c9d4SSatish Balay         }
66059371c9d4SSatish Balay         break;
6606a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
660797e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
660897e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
660997e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
661097e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
6611ba322698SMatthew G. Knepley           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
66129371c9d4SSatish Balay         }
66139371c9d4SSatish Balay         break;
6614552f7358SJed Brown       case ADD_VALUES:
661597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
661697e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
661797e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
661897e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
661997e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
66209371c9d4SSatish Balay         }
66219371c9d4SSatish Balay         break;
6622552f7358SJed Brown       case ADD_ALL_VALUES:
662397e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
662497e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
662597e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
662697e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
662797e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
66289371c9d4SSatish Balay         }
66299371c9d4SSatish Balay         break;
6630304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
663197e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
663297e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
663397e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
663497e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
6635ba322698SMatthew G. Knepley           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
66369371c9d4SSatish Balay         }
66379371c9d4SSatish Balay         break;
6638d71ae5a4SJacob Faibussowitsch       default:
6639d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6640552f7358SJed Brown       }
66419566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
66421a271a75SMatthew G. Knepley     }
6643552f7358SJed Brown   } else {
66441a271a75SMatthew G. Knepley     PetscInt            dof, off;
664597e99dd9SToby Isaac     const PetscInt    **perms = NULL;
664697e99dd9SToby Isaac     const PetscScalar **flips = NULL;
66471a271a75SMatthew G. Knepley 
66489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6649552f7358SJed Brown     switch (mode) {
6650552f7358SJed Brown     case INSERT_VALUES:
665197e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
665297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
665397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
665497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
66559566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
665697e99dd9SToby Isaac         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
66579371c9d4SSatish Balay       }
66589371c9d4SSatish Balay       break;
6659552f7358SJed Brown     case INSERT_ALL_VALUES:
666097e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
666197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
666297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
666397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
66649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
666597e99dd9SToby Isaac         updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
66669371c9d4SSatish Balay       }
66679371c9d4SSatish Balay       break;
6668a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
666997e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
667097e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
667197e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
667297e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
66739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
667497e99dd9SToby Isaac         updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
66759371c9d4SSatish Balay       }
66769371c9d4SSatish Balay       break;
6677552f7358SJed Brown     case ADD_VALUES:
667897e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
667997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
668097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
668197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
66829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
668397e99dd9SToby Isaac         updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
66849371c9d4SSatish Balay       }
66859371c9d4SSatish Balay       break;
6686552f7358SJed Brown     case ADD_ALL_VALUES:
668797e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
668897e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
668997e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
669097e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
66919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
669297e99dd9SToby Isaac         updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
66939371c9d4SSatish Balay       }
66949371c9d4SSatish Balay       break;
6695304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
669697e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
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;
67009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
670197e99dd9SToby Isaac         updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
67029371c9d4SSatish Balay       }
67039371c9d4SSatish Balay       break;
6704d71ae5a4SJacob Faibussowitsch     default:
6705d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6706552f7358SJed Brown     }
67079566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6708552f7358SJed Brown   }
67091a271a75SMatthew G. Knepley   /* Cleanup points */
67109566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
67111a271a75SMatthew G. Knepley   /* Cleanup array */
67129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6713552f7358SJed Brown   PetscFunctionReturn(0);
6714552f7358SJed Brown }
6715552f7358SJed Brown 
67165f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
6717d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
6718d71ae5a4SJacob Faibussowitsch {
67195f790a90SMatthew G. Knepley   PetscFunctionBegin;
672011cc89d2SBarry Smith   *contains = PETSC_TRUE;
67215f790a90SMatthew G. Knepley   if (label) {
6722d6177c40SToby Isaac     PetscInt fdof;
67235f790a90SMatthew G. Knepley 
672411cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
672511cc89d2SBarry Smith     if (!*contains) {
67269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
67275f790a90SMatthew G. Knepley       *offset += fdof;
672811cc89d2SBarry Smith       PetscFunctionReturn(0);
67295f790a90SMatthew G. Knepley     }
67305f790a90SMatthew G. Knepley   }
67315f790a90SMatthew G. Knepley   PetscFunctionReturn(0);
67325f790a90SMatthew G. Knepley }
67335f790a90SMatthew G. Knepley 
673497529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6735d71ae5a4SJacob 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)
6736d71ae5a4SJacob Faibussowitsch {
6737e07394fbSMatthew G. Knepley   PetscSection    clSection;
6738e07394fbSMatthew G. Knepley   IS              clPoints;
6739e07394fbSMatthew G. Knepley   PetscScalar    *array;
6740e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
674197529cf3SJed Brown   const PetscInt *clp;
6742e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
674397e99dd9SToby Isaac   PetscInt        offset = 0, f;
6744e07394fbSMatthew G. Knepley 
6745e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
6746e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
67479566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6748e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6749e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
67509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6751e07394fbSMatthew G. Knepley   /* Get points */
67529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6753e07394fbSMatthew G. Knepley   /* Get array */
67549566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6755e07394fbSMatthew G. Knepley   /* Get values */
6756e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
675797e99dd9SToby Isaac     const PetscInt    **perms = NULL;
675897e99dd9SToby Isaac     const PetscScalar **flips = NULL;
675911cc89d2SBarry Smith     PetscBool           contains;
676097e99dd9SToby Isaac 
6761e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
6762e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
6763e07394fbSMatthew G. Knepley         PetscInt fdof;
67649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6765e07394fbSMatthew G. Knepley         offset += fdof;
6766e07394fbSMatthew G. Knepley       }
6767e07394fbSMatthew G. Knepley       continue;
6768e07394fbSMatthew G. Knepley     }
67699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6770e07394fbSMatthew G. Knepley     switch (mode) {
6771e07394fbSMatthew G. Knepley     case INSERT_VALUES:
677297e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
677397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
677497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
677597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
677611cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
677711cc89d2SBarry Smith         if (!contains) continue;
67789566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
67799371c9d4SSatish Balay       }
67809371c9d4SSatish Balay       break;
6781e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
678297e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
678397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
678497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
678597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
678611cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
678711cc89d2SBarry Smith         if (!contains) continue;
67889566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
67899371c9d4SSatish Balay       }
67909371c9d4SSatish Balay       break;
6791e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
679297e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
679397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
679497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
679597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
679611cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
679711cc89d2SBarry Smith         if (!contains) continue;
67989566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
67999371c9d4SSatish Balay       }
68009371c9d4SSatish Balay       break;
6801e07394fbSMatthew G. Knepley     case ADD_VALUES:
680297e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
680397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
680497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
680597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
680611cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
680711cc89d2SBarry Smith         if (!contains) continue;
68089566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
68099371c9d4SSatish Balay       }
68109371c9d4SSatish Balay       break;
6811e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
681297e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
681397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
681497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
681597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
681611cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
681711cc89d2SBarry Smith         if (!contains) continue;
68189566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
68199371c9d4SSatish Balay       }
68209371c9d4SSatish Balay       break;
6821d71ae5a4SJacob Faibussowitsch     default:
6822d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6823e07394fbSMatthew G. Knepley     }
68249566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6825e07394fbSMatthew G. Knepley   }
6826e07394fbSMatthew G. Knepley   /* Cleanup points */
68279566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6828e07394fbSMatthew G. Knepley   /* Cleanup array */
68299566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6830e07394fbSMatthew G. Knepley   PetscFunctionReturn(0);
6831e07394fbSMatthew G. Knepley }
6832e07394fbSMatthew G. Knepley 
6833d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6834d71ae5a4SJacob Faibussowitsch {
6835552f7358SJed Brown   PetscMPIInt rank;
6836552f7358SJed Brown   PetscInt    i, j;
6837552f7358SJed Brown 
6838552f7358SJed Brown   PetscFunctionBegin;
68399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
684063a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
684163a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
684263a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
6843b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
6844557cf195SMatthew G. Knepley   if (!values) PetscFunctionReturn(0);
6845b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
68469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6847b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
6848519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
68499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
6850552f7358SJed Brown #else
68519566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
6852552f7358SJed Brown #endif
6853552f7358SJed Brown     }
68549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
6855552f7358SJed Brown   }
6856552f7358SJed Brown   PetscFunctionReturn(0);
6857552f7358SJed Brown }
6858552f7358SJed Brown 
685905586334SMatthew G. Knepley /*
686005586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
686105586334SMatthew G. Knepley 
686205586334SMatthew G. Knepley   Input Parameters:
686305586334SMatthew G. Knepley + section - The section for this data layout
686436fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
686505586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
686605586334SMatthew G. Knepley . off     - The global offset of this point
686705586334SMatthew G. Knepley . loff    - The local offset of each field
6868a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
686905586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
687005586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
687105586334SMatthew G. Knepley 
687205586334SMatthew G. Knepley   Output Parameter:
687305586334SMatthew G. Knepley . indices - Indices for dofs on this point
687405586334SMatthew G. Knepley 
687505586334SMatthew G. Knepley   Level: developer
687605586334SMatthew G. Knepley 
687705586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
687805586334SMatthew G. Knepley */
6879d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6880d71ae5a4SJacob Faibussowitsch {
6881e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
6882552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6883552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6884552f7358SJed Brown   PetscInt        cind = 0, k;
6885552f7358SJed Brown 
6886552f7358SJed Brown   PetscFunctionBegin;
688708401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
68889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
68899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6890552f7358SJed Brown   if (!cdof || setBC) {
689105586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
689205586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
689305586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
689405586334SMatthew G. Knepley 
689505586334SMatthew G. Knepley       indices[ind] = off + k;
6896552f7358SJed Brown     }
6897552f7358SJed Brown   } else {
68989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
68994acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
690005586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
690105586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
690205586334SMatthew G. Knepley 
69034acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
69044acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
690505586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
69064acb8e1eSToby Isaac         ++cind;
69074acb8e1eSToby Isaac       } else {
690836fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
6909552f7358SJed Brown       }
6910552f7358SJed Brown     }
6911552f7358SJed Brown   }
6912e6ccafaeSMatthew G Knepley   *loff += dof;
6913552f7358SJed Brown   PetscFunctionReturn(0);
6914552f7358SJed Brown }
6915552f7358SJed Brown 
69167e29afd2SMatthew G. Knepley /*
691736fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
69187e29afd2SMatthew G. Knepley 
691936fa2b79SJed Brown  Input Parameters:
692036fa2b79SJed Brown + section - a section (global or local)
692136fa2b79SJed Brown - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
692236fa2b79SJed Brown . point - point within section
692336fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
692436fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
692536fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
692636fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
692736fa2b79SJed Brown . permsoff - offset
692836fa2b79SJed Brown - indperm - index permutation
692936fa2b79SJed Brown 
693036fa2b79SJed Brown  Output Parameter:
693136fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
693236fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
693336fa2b79SJed Brown 
693436fa2b79SJed Brown  Notes:
693536fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
693636fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
693736fa2b79SJed Brown  in the local vector.
693836fa2b79SJed Brown 
693936fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
694036fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
694136fa2b79SJed Brown 
694236fa2b79SJed Brown  Developer Note:
694336fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
694436fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
694536fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
694636fa2b79SJed Brown 
694736fa2b79SJed Brown  Example:
694836fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
694936fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
695036fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
695136fa2b79SJed 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.
695236fa2b79SJed Brown 
695336fa2b79SJed Brown  Level: developer
69547e29afd2SMatthew G. Knepley */
6955d71ae5a4SJacob 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[])
6956d71ae5a4SJacob Faibussowitsch {
6957552f7358SJed Brown   PetscInt numFields, foff, f;
6958552f7358SJed Brown 
6959552f7358SJed Brown   PetscFunctionBegin;
696008401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
69619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6962552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
69634acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
6964552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
69654acb8e1eSToby Isaac     PetscInt        cind = 0, b;
69664acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6967552f7358SJed Brown 
69689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
69699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
6970552f7358SJed Brown     if (!cfdof || setBC) {
697105586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
697205586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
697305586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
697405586334SMatthew G. Knepley 
697505586334SMatthew G. Knepley         indices[ind] = off + foff + b;
697605586334SMatthew G. Knepley       }
6977552f7358SJed Brown     } else {
69789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
697905586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
698005586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
698105586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
698205586334SMatthew G. Knepley 
69834acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
698405586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
6985552f7358SJed Brown           ++cind;
6986552f7358SJed Brown         } else {
698736fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6988552f7358SJed Brown         }
6989552f7358SJed Brown       }
6990552f7358SJed Brown     }
699136fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
6992552f7358SJed Brown     foffs[f] += fdof;
6993552f7358SJed Brown   }
6994552f7358SJed Brown   PetscFunctionReturn(0);
6995552f7358SJed Brown }
6996552f7358SJed Brown 
69977e29afd2SMatthew G. Knepley /*
69987e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
69997e29afd2SMatthew G. Knepley 
70007e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7001645102dcSJed Brown 
7002645102dcSJed Brown  Notes:
7003645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7004645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
70057e29afd2SMatthew G. Knepley */
7006d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7007d71ae5a4SJacob Faibussowitsch {
70087e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
70097e29afd2SMatthew G. Knepley 
70107e29afd2SMatthew G. Knepley   PetscFunctionBegin;
70119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
70127e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
70137e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
70147e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
70157e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
70167e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
70177e29afd2SMatthew G. Knepley 
70189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
70199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
70209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7021645102dcSJed Brown     if (!cfdof) {
702205586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
702305586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
702405586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
702505586334SMatthew G. Knepley 
702605586334SMatthew G. Knepley         indices[ind] = foff + b;
702705586334SMatthew G. Knepley       }
70287e29afd2SMatthew G. Knepley     } else {
70299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
703005586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
703105586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
703205586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
703305586334SMatthew G. Knepley 
70347e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
703505586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
70367e29afd2SMatthew G. Knepley           ++cind;
70377e29afd2SMatthew G. Knepley         } else {
703805586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
70397e29afd2SMatthew G. Knepley         }
70407e29afd2SMatthew G. Knepley       }
70417e29afd2SMatthew G. Knepley     }
70427e29afd2SMatthew G. Knepley     foffs[f] += fdof;
70437e29afd2SMatthew G. Knepley   }
70447e29afd2SMatthew G. Knepley   PetscFunctionReturn(0);
70457e29afd2SMatthew G. Knepley }
70467e29afd2SMatthew G. Knepley 
7047d71ae5a4SJacob 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)
7048d71ae5a4SJacob Faibussowitsch {
7049d3d1a6afSToby Isaac   Mat             cMat;
7050d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7051d3d1a6afSToby Isaac   IS              aIS;
7052d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7053d3d1a6afSToby Isaac   const PetscInt *anchors;
7054e17c06e0SMatthew G. Knepley   PetscInt        numFields, f, p, q, newP = 0;
7055d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7056d3d1a6afSToby Isaac   PetscInt       *newPoints, *indices, *newIndices;
7057d3d1a6afSToby Isaac   PetscInt        maxAnchor, maxDof;
7058d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7059d3d1a6afSToby Isaac   PetscInt       *pointMatOffsets[32];
7060d3d1a6afSToby Isaac   PetscInt       *newPointOffsets[32];
7061d3d1a6afSToby Isaac   PetscScalar    *pointMat[32];
70626ecaa68aSToby Isaac   PetscScalar    *newValues      = NULL, *tmpValues;
7063d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7064d3d1a6afSToby Isaac 
7065d3d1a6afSToby Isaac   PetscFunctionBegin;
7066d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7067d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
70689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7069d3d1a6afSToby Isaac 
70709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7071d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7072d3d1a6afSToby Isaac   if (aSec) {
70739566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
70749566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
70759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7076d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7077d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7078d3d1a6afSToby Isaac      * into the global matrix anyway) */
7079d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7080d3d1a6afSToby Isaac       PetscInt b    = points[p];
70814b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7082d3d1a6afSToby Isaac 
70839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7084ad540459SPierre Jolivet       if (!bSecDof) continue;
708548a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7086d3d1a6afSToby Isaac       if (bDof) {
7087d3d1a6afSToby Isaac         /* this point is constrained */
7088d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7089d3d1a6afSToby Isaac         PetscInt bOff, q;
7090d3d1a6afSToby Isaac 
7091d3d1a6afSToby Isaac         anyConstrained = PETSC_TRUE;
7092d3d1a6afSToby Isaac         newNumPoints += bDof;
70939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7094d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7095d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q];
7096d3d1a6afSToby Isaac           PetscInt aDof;
7097d3d1a6afSToby Isaac 
70989566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7099d3d1a6afSToby Isaac           newNumIndices += aDof;
7100d3d1a6afSToby Isaac           for (f = 0; f < numFields; ++f) {
7101d3d1a6afSToby Isaac             PetscInt fDof;
7102d3d1a6afSToby Isaac 
71039566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7104d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7105d3d1a6afSToby Isaac           }
7106d3d1a6afSToby Isaac         }
71079371c9d4SSatish Balay       } else {
7108d3d1a6afSToby Isaac         /* this point is not constrained */
7109d3d1a6afSToby Isaac         newNumPoints++;
71104b2f2278SToby Isaac         newNumIndices += bSecDof;
7111d3d1a6afSToby Isaac         for (f = 0; f < numFields; ++f) {
7112d3d1a6afSToby Isaac           PetscInt fDof;
7113d3d1a6afSToby Isaac 
71149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7115d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7116d3d1a6afSToby Isaac         }
7117d3d1a6afSToby Isaac       }
7118d3d1a6afSToby Isaac     }
7119d3d1a6afSToby Isaac   }
7120d3d1a6afSToby Isaac   if (!anyConstrained) {
712172b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
712272b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
712372b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
712472b80496SMatthew G. Knepley     if (outValues) *outValues = NULL;
71259566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7126d3d1a6afSToby Isaac     PetscFunctionReturn(0);
7127d3d1a6afSToby Isaac   }
7128d3d1a6afSToby Isaac 
71296ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
71306ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
71316ecaa68aSToby Isaac 
7132f13f9184SToby Isaac   for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7133d3d1a6afSToby Isaac 
71346ecaa68aSToby Isaac   if (!outPoints && !outValues) {
71356ecaa68aSToby Isaac     if (offsets) {
7136ad540459SPierre Jolivet       for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
71376ecaa68aSToby Isaac     }
71389566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
71396ecaa68aSToby Isaac     PetscFunctionReturn(0);
71406ecaa68aSToby Isaac   }
71416ecaa68aSToby Isaac 
71421dca8a05SBarry 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);
7143d3d1a6afSToby Isaac 
71449566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7145d3d1a6afSToby Isaac 
7146d3d1a6afSToby Isaac   /* workspaces */
7147d3d1a6afSToby Isaac   if (numFields) {
7148d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
71499566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
71509566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7151d3d1a6afSToby Isaac     }
71529371c9d4SSatish Balay   } else {
71539566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
71549566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0]));
7155d3d1a6afSToby Isaac   }
7156d3d1a6afSToby Isaac 
7157d3d1a6afSToby Isaac   /* get workspaces for the point-to-point matrices */
7158d3d1a6afSToby Isaac   if (numFields) {
71594b2f2278SToby Isaac     PetscInt totalOffset, totalMatOffset;
71604b2f2278SToby Isaac 
7161d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7162d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
71634b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7164d3d1a6afSToby Isaac 
71659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
71664b2f2278SToby Isaac       if (!bSecDof) {
71674b2f2278SToby Isaac         for (f = 0; f < numFields; f++) {
71684b2f2278SToby Isaac           newPointOffsets[f][p + 1] = 0;
71694b2f2278SToby Isaac           pointMatOffsets[f][p + 1] = 0;
71704b2f2278SToby Isaac         }
71714b2f2278SToby Isaac         continue;
71724b2f2278SToby Isaac       }
717348a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7174d3d1a6afSToby Isaac       if (bDof) {
7175d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7176d3d1a6afSToby Isaac           PetscInt fDof, q, bOff, allFDof = 0;
7177d3d1a6afSToby Isaac 
71789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
71799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7180d3d1a6afSToby Isaac           for (q = 0; q < bDof; q++) {
7181d3d1a6afSToby Isaac             PetscInt a = anchors[bOff + q];
7182d3d1a6afSToby Isaac             PetscInt aFDof;
7183d3d1a6afSToby Isaac 
71849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
7185d3d1a6afSToby Isaac             allFDof += aFDof;
7186d3d1a6afSToby Isaac           }
7187d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = allFDof;
7188d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = fDof * allFDof;
7189d3d1a6afSToby Isaac         }
71909371c9d4SSatish Balay       } else {
7191d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7192d3d1a6afSToby Isaac           PetscInt fDof;
7193d3d1a6afSToby Isaac 
71949566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7195d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = fDof;
7196d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = 0;
7197d3d1a6afSToby Isaac         }
7198d3d1a6afSToby Isaac       }
7199d3d1a6afSToby Isaac     }
72004b2f2278SToby Isaac     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
72014b2f2278SToby Isaac       newPointOffsets[f][0] = totalOffset;
72024b2f2278SToby Isaac       pointMatOffsets[f][0] = totalMatOffset;
7203d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7204d3d1a6afSToby Isaac         newPointOffsets[f][p + 1] += newPointOffsets[f][p];
7205d3d1a6afSToby Isaac         pointMatOffsets[f][p + 1] += pointMatOffsets[f][p];
7206d3d1a6afSToby Isaac       }
720719f70fd5SToby Isaac       totalOffset    = newPointOffsets[f][numPoints];
720819f70fd5SToby Isaac       totalMatOffset = pointMatOffsets[f][numPoints];
72099566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7210d3d1a6afSToby Isaac     }
72119371c9d4SSatish Balay   } else {
7212d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7213d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
72144b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7215d3d1a6afSToby Isaac 
72169566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
72174b2f2278SToby Isaac       if (!bSecDof) {
72184b2f2278SToby Isaac         newPointOffsets[0][p + 1] = 0;
72194b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = 0;
72204b2f2278SToby Isaac         continue;
72214b2f2278SToby Isaac       }
722248a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7223d3d1a6afSToby Isaac       if (bDof) {
72244b2f2278SToby Isaac         PetscInt bOff, q, allDof = 0;
7225d3d1a6afSToby Isaac 
72269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7227d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7228d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aDof;
7229d3d1a6afSToby Isaac 
72309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7231d3d1a6afSToby Isaac           allDof += aDof;
7232d3d1a6afSToby Isaac         }
7233d3d1a6afSToby Isaac         newPointOffsets[0][p + 1] = allDof;
72344b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = bSecDof * allDof;
72359371c9d4SSatish Balay       } else {
72364b2f2278SToby Isaac         newPointOffsets[0][p + 1] = bSecDof;
7237d3d1a6afSToby Isaac         pointMatOffsets[0][p + 1] = 0;
7238d3d1a6afSToby Isaac       }
7239d3d1a6afSToby Isaac     }
7240d3d1a6afSToby Isaac     newPointOffsets[0][0] = 0;
7241d3d1a6afSToby Isaac     pointMatOffsets[0][0] = 0;
7242d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7243d3d1a6afSToby Isaac       newPointOffsets[0][p + 1] += newPointOffsets[0][p];
7244d3d1a6afSToby Isaac       pointMatOffsets[0][p + 1] += pointMatOffsets[0][p];
7245d3d1a6afSToby Isaac     }
72469566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7247d3d1a6afSToby Isaac   }
7248d3d1a6afSToby Isaac 
72496ecaa68aSToby Isaac   /* output arrays */
72509566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
72516ecaa68aSToby Isaac 
7252d3d1a6afSToby Isaac   /* get the point-to-point matrices; construct newPoints */
72539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
72549566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
72559566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices));
72569566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7257d3d1a6afSToby Isaac   if (numFields) {
7258d3d1a6afSToby Isaac     for (p = 0, newP = 0; p < numPoints; p++) {
7259d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7260d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
72614b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7262d3d1a6afSToby Isaac 
72639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7264ad540459SPierre Jolivet       if (!bSecDof) continue;
726548a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7266d3d1a6afSToby Isaac       if (bDof) {
7267d3d1a6afSToby Isaac         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
7268d3d1a6afSToby Isaac 
7269d3d1a6afSToby Isaac         fStart[0] = 0;
7270d3d1a6afSToby Isaac         fEnd[0]   = 0;
7271d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7272d3d1a6afSToby Isaac           PetscInt fDof;
7273d3d1a6afSToby Isaac 
72749566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7275d3d1a6afSToby Isaac           fStart[f + 1] = fStart[f] + fDof;
7276d3d1a6afSToby Isaac           fEnd[f + 1]   = fStart[f + 1];
7277d3d1a6afSToby Isaac         }
72789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
72799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
7280d3d1a6afSToby Isaac 
7281d3d1a6afSToby Isaac         fAnchorStart[0] = 0;
7282d3d1a6afSToby Isaac         fAnchorEnd[0]   = 0;
7283d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7284d3d1a6afSToby Isaac           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7285d3d1a6afSToby Isaac 
7286d3d1a6afSToby Isaac           fAnchorStart[f + 1] = fAnchorStart[f] + fDof;
7287d3d1a6afSToby Isaac           fAnchorEnd[f + 1]   = fAnchorStart[f + 1];
7288d3d1a6afSToby Isaac         }
72899566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7290d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7291d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7292d3d1a6afSToby Isaac 
7293d3d1a6afSToby 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 */
7294d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7295d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
72969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
72979566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7298d3d1a6afSToby Isaac         }
7299d3d1a6afSToby Isaac         newP += bDof;
7300d3d1a6afSToby Isaac 
73016ecaa68aSToby Isaac         if (outValues) {
7302d3d1a6afSToby Isaac           /* get the point-to-point submatrix */
730348a46eb9SPierre 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]));
7304d3d1a6afSToby Isaac         }
73059371c9d4SSatish Balay       } else {
7306d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7307d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7308d3d1a6afSToby Isaac         newP++;
7309d3d1a6afSToby Isaac       }
7310d3d1a6afSToby Isaac     }
7311d3d1a6afSToby Isaac   } else {
7312d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7313d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7314d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
73154b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7316d3d1a6afSToby Isaac 
73179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7318ad540459SPierre Jolivet       if (!bSecDof) continue;
731948a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7320d3d1a6afSToby Isaac       if (bDof) {
7321d3d1a6afSToby Isaac         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7322d3d1a6afSToby Isaac 
73239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
73249566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7325d3d1a6afSToby Isaac 
73269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7327d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7328d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7329d3d1a6afSToby Isaac 
7330d3d1a6afSToby 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 */
7331d3d1a6afSToby Isaac 
7332d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7333d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
73349566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
73359566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7336d3d1a6afSToby Isaac         }
7337d3d1a6afSToby Isaac         newP += bDof;
7338d3d1a6afSToby Isaac 
7339d3d1a6afSToby Isaac         /* get the point-to-point submatrix */
734048a46eb9SPierre Jolivet         if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p]));
73419371c9d4SSatish Balay       } else {
7342d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7343d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7344d3d1a6afSToby Isaac         newP++;
7345d3d1a6afSToby Isaac       }
7346d3d1a6afSToby Isaac     }
7347d3d1a6afSToby Isaac   }
7348d3d1a6afSToby Isaac 
73496ecaa68aSToby Isaac   if (outValues) {
73509566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
73519566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices));
7352d3d1a6afSToby Isaac     /* multiply constraints on the right */
7353d3d1a6afSToby Isaac     if (numFields) {
7354d3d1a6afSToby Isaac       for (f = 0; f < numFields; f++) {
7355d3d1a6afSToby Isaac         PetscInt oldOff = offsets[f];
7356d3d1a6afSToby Isaac 
7357d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7358d3d1a6afSToby Isaac           PetscInt cStart = newPointOffsets[f][p];
7359d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7360d3d1a6afSToby Isaac           PetscInt c, r, k;
7361d3d1a6afSToby Isaac           PetscInt dof;
7362d3d1a6afSToby Isaac 
73639566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7364ad540459SPierre Jolivet           if (!dof) continue;
7365d3d1a6afSToby Isaac           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7366d3d1a6afSToby Isaac             PetscInt           nCols = newPointOffsets[f][p + 1] - cStart;
7367d3d1a6afSToby Isaac             const PetscScalar *mat   = pointMat[f] + pointMatOffsets[f][p];
7368d3d1a6afSToby Isaac 
7369d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7370d3d1a6afSToby Isaac               for (c = 0; c < nCols; c++) {
7371ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7372d3d1a6afSToby Isaac               }
7373d3d1a6afSToby Isaac             }
73749371c9d4SSatish Balay           } else {
7375d3d1a6afSToby Isaac             /* copy this column as is */
7376d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7377ad540459SPierre Jolivet               for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7378d3d1a6afSToby Isaac             }
7379d3d1a6afSToby Isaac           }
7380d3d1a6afSToby Isaac           oldOff += dof;
7381d3d1a6afSToby Isaac         }
7382d3d1a6afSToby Isaac       }
73839371c9d4SSatish Balay     } else {
7384d3d1a6afSToby Isaac       PetscInt oldOff = 0;
7385d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7386d3d1a6afSToby Isaac         PetscInt cStart = newPointOffsets[0][p];
7387d3d1a6afSToby Isaac         PetscInt b      = points[2 * p];
7388d3d1a6afSToby Isaac         PetscInt c, r, k;
7389d3d1a6afSToby Isaac         PetscInt dof;
7390d3d1a6afSToby Isaac 
73919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, b, &dof));
7392ad540459SPierre Jolivet         if (!dof) continue;
7393d3d1a6afSToby Isaac         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7394d3d1a6afSToby Isaac           PetscInt           nCols = newPointOffsets[0][p + 1] - cStart;
7395d3d1a6afSToby Isaac           const PetscScalar *mat   = pointMat[0] + pointMatOffsets[0][p];
7396d3d1a6afSToby Isaac 
7397d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7398d3d1a6afSToby Isaac             for (c = 0; c < nCols; c++) {
7399ad540459SPierre Jolivet               for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7400d3d1a6afSToby Isaac             }
7401d3d1a6afSToby Isaac           }
74029371c9d4SSatish Balay         } else {
7403d3d1a6afSToby Isaac           /* copy this column as is */
7404d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7405ad540459SPierre Jolivet             for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7406d3d1a6afSToby Isaac           }
7407d3d1a6afSToby Isaac         }
7408d3d1a6afSToby Isaac         oldOff += dof;
7409d3d1a6afSToby Isaac       }
7410d3d1a6afSToby Isaac     }
7411d3d1a6afSToby Isaac 
74126ecaa68aSToby Isaac     if (multiplyLeft) {
74139566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues));
74149566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices));
7415d3d1a6afSToby Isaac       /* multiply constraints transpose on the left */
7416d3d1a6afSToby Isaac       if (numFields) {
7417d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7418d3d1a6afSToby Isaac           PetscInt oldOff = offsets[f];
7419d3d1a6afSToby Isaac 
7420d3d1a6afSToby Isaac           for (p = 0; p < numPoints; p++) {
7421d3d1a6afSToby Isaac             PetscInt rStart = newPointOffsets[f][p];
7422d3d1a6afSToby Isaac             PetscInt b      = points[2 * p];
7423d3d1a6afSToby Isaac             PetscInt c, r, k;
7424d3d1a6afSToby Isaac             PetscInt dof;
7425d3d1a6afSToby Isaac 
74269566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7427d3d1a6afSToby Isaac             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7428d3d1a6afSToby Isaac               PetscInt                          nRows = newPointOffsets[f][p + 1] - rStart;
7429d3d1a6afSToby Isaac               const PetscScalar *PETSC_RESTRICT mat   = pointMat[f] + pointMatOffsets[f][p];
7430d3d1a6afSToby Isaac 
7431d3d1a6afSToby Isaac               for (r = 0; r < nRows; r++) {
7432d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7433ad540459SPierre Jolivet                   for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7434d3d1a6afSToby Isaac                 }
7435d3d1a6afSToby Isaac               }
74369371c9d4SSatish Balay             } else {
7437d3d1a6afSToby Isaac               /* copy this row as is */
7438d3d1a6afSToby Isaac               for (r = 0; r < dof; r++) {
7439ad540459SPierre Jolivet                 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7440d3d1a6afSToby Isaac               }
7441d3d1a6afSToby Isaac             }
7442d3d1a6afSToby Isaac             oldOff += dof;
7443d3d1a6afSToby Isaac           }
7444d3d1a6afSToby Isaac         }
74459371c9d4SSatish Balay       } else {
7446d3d1a6afSToby Isaac         PetscInt oldOff = 0;
7447d3d1a6afSToby Isaac 
7448d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7449d3d1a6afSToby Isaac           PetscInt rStart = newPointOffsets[0][p];
7450d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7451d3d1a6afSToby Isaac           PetscInt c, r, k;
7452d3d1a6afSToby Isaac           PetscInt dof;
7453d3d1a6afSToby Isaac 
74549566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, b, &dof));
7455d3d1a6afSToby Isaac           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7456d3d1a6afSToby Isaac             PetscInt                          nRows = newPointOffsets[0][p + 1] - rStart;
7457d3d1a6afSToby Isaac             const PetscScalar *PETSC_RESTRICT mat   = pointMat[0] + pointMatOffsets[0][p];
7458d3d1a6afSToby Isaac 
7459d3d1a6afSToby Isaac             for (r = 0; r < nRows; r++) {
7460d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7461ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7462d3d1a6afSToby Isaac               }
7463d3d1a6afSToby Isaac             }
74649371c9d4SSatish Balay           } else {
7465d3d1a6afSToby Isaac             /* copy this row as is */
74669fc93327SToby Isaac             for (r = 0; r < dof; r++) {
7467ad540459SPierre Jolivet               for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7468d3d1a6afSToby Isaac             }
7469d3d1a6afSToby Isaac           }
7470d3d1a6afSToby Isaac           oldOff += dof;
7471d3d1a6afSToby Isaac         }
7472d3d1a6afSToby Isaac       }
7473d3d1a6afSToby Isaac 
74749566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
74759371c9d4SSatish Balay     } else {
74766ecaa68aSToby Isaac       newValues = tmpValues;
74776ecaa68aSToby Isaac     }
74786ecaa68aSToby Isaac   }
74796ecaa68aSToby Isaac 
7480d3d1a6afSToby Isaac   /* clean up */
74819566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices));
74829566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
74836ecaa68aSToby Isaac 
7484d3d1a6afSToby Isaac   if (numFields) {
7485d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
74869566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
74879566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
74889566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7489d3d1a6afSToby Isaac     }
74909371c9d4SSatish Balay   } else {
74919566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
74929566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
74939566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0]));
7494d3d1a6afSToby Isaac   }
74959566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
7496d3d1a6afSToby Isaac 
7497d3d1a6afSToby Isaac   /* output */
74986ecaa68aSToby Isaac   if (outPoints) {
7499d3d1a6afSToby Isaac     *outPoints = newPoints;
75009371c9d4SSatish Balay   } else {
75019566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
75026ecaa68aSToby Isaac   }
7503ad540459SPierre Jolivet   if (outValues) *outValues = newValues;
7504ad540459SPierre Jolivet   for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7505d3d1a6afSToby Isaac   PetscFunctionReturn(0);
7506d3d1a6afSToby Isaac }
7507d3d1a6afSToby Isaac 
75084a1e0b3eSMatthew G. Knepley /*@C
750971f0bbf9SMatthew G. Knepley   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
75107cd05799SMatthew G. Knepley 
75117cd05799SMatthew G. Knepley   Not collective
75127cd05799SMatthew G. Knepley 
75137cd05799SMatthew G. Knepley   Input Parameters:
75147cd05799SMatthew G. Knepley + dm         - The DM
751571f0bbf9SMatthew G. Knepley . section    - The PetscSection describing the points (a local section)
751671f0bbf9SMatthew G. Knepley . idxSection - The PetscSection from which to obtain indices (may be local or global)
751771f0bbf9SMatthew G. Knepley . point      - The point defining the closure
751871f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
75197cd05799SMatthew G. Knepley 
752071f0bbf9SMatthew G. Knepley   Output Parameters:
752171f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
752271f0bbf9SMatthew G. Knepley . indices    - The dof indices
752371f0bbf9SMatthew G. Knepley . outOffsets - Array to write the field offsets into, or NULL
752471f0bbf9SMatthew G. Knepley - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
75257cd05799SMatthew G. Knepley 
752636fa2b79SJed Brown   Notes:
752736fa2b79SJed Brown   Must call DMPlexRestoreClosureIndices() to free allocated memory
752836fa2b79SJed Brown 
752936fa2b79SJed Brown   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
753036fa2b79SJed Brown   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
753136fa2b79SJed Brown   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
753236fa2b79SJed Brown   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
753336fa2b79SJed Brown   indices (with the above semantics) are implied.
75347cd05799SMatthew G. Knepley 
75357cd05799SMatthew G. Knepley   Level: advanced
75367cd05799SMatthew G. Knepley 
7537db781477SPatrick Sanan .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
75384a1e0b3eSMatthew G. Knepley @*/
7539d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7540d71ae5a4SJacob Faibussowitsch {
754171f0bbf9SMatthew G. Knepley   /* Closure ordering */
75427773e69fSMatthew G. Knepley   PetscSection    clSection;
75437773e69fSMatthew G. Knepley   IS              clPoints;
754471f0bbf9SMatthew G. Knepley   const PetscInt *clp;
754571f0bbf9SMatthew G. Knepley   PetscInt       *points;
754671f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
754771f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
75484acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
754971f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
755071f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
755171f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
755271f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
755371f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
755471f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
755571f0bbf9SMatthew G. Knepley 
755671f0bbf9SMatthew G. Knepley   PetscInt *idx;
755771f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
755871f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
75597773e69fSMatthew G. Knepley 
756071f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
75617773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
75627773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
756336fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7564dadcf809SJacob Faibussowitsch   if (numIndices) PetscValidIntPointer(numIndices, 6);
756571f0bbf9SMatthew G. Knepley   if (indices) PetscValidPointer(indices, 7);
7566dadcf809SJacob Faibussowitsch   if (outOffsets) PetscValidIntPointer(outOffsets, 8);
756771f0bbf9SMatthew G. Knepley   if (values) PetscValidPointer(values, 9);
75689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
756963a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
75709566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
757171f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
75729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7573c459fbc1SJed Brown   if (useClPerm) {
7574c459fbc1SJed Brown     PetscInt depth, clsize;
75759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7576c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
7577c459fbc1SJed Brown       PetscInt dof;
75789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7579c459fbc1SJed Brown       clsize += dof;
7580c459fbc1SJed Brown     }
75819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7582c459fbc1SJed Brown   }
758371f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
758471f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
75857773e69fSMatthew G. Knepley     PetscInt dof, fdof;
75867773e69fSMatthew G. Knepley 
75879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
75887773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
75899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
75907773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
75917773e69fSMatthew G. Knepley     }
759271f0bbf9SMatthew G. Knepley     Ni += dof;
75937773e69fSMatthew G. Knepley   }
75947773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
75951dca8a05SBarry 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);
759671f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
759771f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
75989566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
75999566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
760071f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
760171f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
760271f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
76036ecaa68aSToby Isaac 
760471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
760571f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
760671f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
760771f0bbf9SMatthew G. Knepley 
76089566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
76099566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
761071f0bbf9SMatthew G. Knepley         if (flip) {
761171f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
761271f0bbf9SMatthew G. Knepley 
761371f0bbf9SMatthew G. Knepley           if (!valCopy) {
76149566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
761571f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
761671f0bbf9SMatthew G. Knepley             *values = valCopy;
761771f0bbf9SMatthew G. Knepley           }
761871f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
761971f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
762071f0bbf9SMatthew G. Knepley 
762171f0bbf9SMatthew G. Knepley             for (k = 0; k < Ni; ++k) {
762271f0bbf9SMatthew G. Knepley               valCopy[Ni * (foffset + i) + k] *= fval;
762371f0bbf9SMatthew G. Knepley               valCopy[Ni * k + (foffset + i)] *= fval;
76246ecaa68aSToby Isaac             }
76256ecaa68aSToby Isaac           }
762671f0bbf9SMatthew G. Knepley         }
762771f0bbf9SMatthew G. Knepley         foffset += fdof;
762871f0bbf9SMatthew G. Knepley       }
762971f0bbf9SMatthew G. Knepley     }
763071f0bbf9SMatthew G. Knepley   }
763171f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
76329566063dSJacob Faibussowitsch   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
763371f0bbf9SMatthew G. Knepley   if (NclC) {
76349566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
763571f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
76369566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
76379566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
763871f0bbf9SMatthew G. Knepley     }
763971f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
76409566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
76419566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
764271f0bbf9SMatthew G. Knepley     }
76439566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
764471f0bbf9SMatthew G. Knepley     Ncl    = NclC;
764571f0bbf9SMatthew G. Knepley     Ni     = NiC;
764671f0bbf9SMatthew G. Knepley     points = pointsC;
764771f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
764871f0bbf9SMatthew G. Knepley   }
764971f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
76509566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
765171f0bbf9SMatthew G. Knepley   if (Nf) {
765271f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
765371f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
765471f0bbf9SMatthew G. Knepley 
76559371c9d4SSatish Balay     if (outOffsets) {
76569371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
76579371c9d4SSatish Balay     }
76589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
765971f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
766071f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
766171f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
766271f0bbf9SMatthew G. Knepley 
76639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
76647773e69fSMatthew G. Knepley       }
76657773e69fSMatthew G. Knepley     } else {
766671f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
766771f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
766871f0bbf9SMatthew G. Knepley 
76699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
767071f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
767171f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
767271f0bbf9SMatthew G. Knepley          * global section. */
76739566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
767471f0bbf9SMatthew G. Knepley       }
767571f0bbf9SMatthew G. Knepley     }
767671f0bbf9SMatthew G. Knepley   } else {
767771f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
767871f0bbf9SMatthew G. Knepley 
767971f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
768071f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
76814acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
76824acb8e1eSToby Isaac 
76839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
768471f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
768571f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
76869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
76877773e69fSMatthew G. Knepley     }
76887773e69fSMatthew G. Knepley   }
768971f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
769071f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
76919566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
76929566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
76934acb8e1eSToby Isaac   }
769471f0bbf9SMatthew G. Knepley   if (NclC) {
76959566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
76967773e69fSMatthew G. Knepley   } else {
76979566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
76987773e69fSMatthew G. Knepley   }
769971f0bbf9SMatthew G. Knepley 
770071f0bbf9SMatthew G. Knepley   if (numIndices) *numIndices = Ni;
770171f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
77027773e69fSMatthew G. Knepley   PetscFunctionReturn(0);
77037773e69fSMatthew G. Knepley }
77047773e69fSMatthew G. Knepley 
77057cd05799SMatthew G. Knepley /*@C
770671f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
77077cd05799SMatthew G. Knepley 
77087cd05799SMatthew G. Knepley   Not collective
77097cd05799SMatthew G. Knepley 
77107cd05799SMatthew G. Knepley   Input Parameters:
77117cd05799SMatthew G. Knepley + dm         - The DM
771271f0bbf9SMatthew G. Knepley . section    - The PetscSection describing the points (a local section)
771371f0bbf9SMatthew G. Knepley . idxSection - The PetscSection from which to obtain indices (may be local or global)
771471f0bbf9SMatthew G. Knepley . point      - The point defining the closure
771571f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
771671f0bbf9SMatthew G. Knepley 
771771f0bbf9SMatthew G. Knepley   Output Parameters:
771871f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
771971f0bbf9SMatthew G. Knepley . indices    - The dof indices
772071f0bbf9SMatthew G. Knepley . outOffsets - Array to write the field offsets into, or NULL
772171f0bbf9SMatthew G. Knepley - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
772271f0bbf9SMatthew G. Knepley 
772371f0bbf9SMatthew G. Knepley   Notes:
772471f0bbf9SMatthew G. Knepley   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
772571f0bbf9SMatthew G. Knepley 
772671f0bbf9SMatthew G. Knepley   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
772771f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
772871f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
772971f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
773071f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
77317cd05799SMatthew G. Knepley 
77327cd05799SMatthew G. Knepley   Level: advanced
77337cd05799SMatthew G. Knepley 
7734db781477SPatrick Sanan .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
77357cd05799SMatthew G. Knepley @*/
7736d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7737d71ae5a4SJacob Faibussowitsch {
77387773e69fSMatthew G. Knepley   PetscFunctionBegin;
77397773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7740064a246eSJacob Faibussowitsch   PetscValidPointer(indices, 7);
77419566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
77427773e69fSMatthew G. Knepley   PetscFunctionReturn(0);
77437773e69fSMatthew G. Knepley }
77447773e69fSMatthew G. Knepley 
77457f5d1fdeSMatthew G. Knepley /*@C
77467f5d1fdeSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
77477f5d1fdeSMatthew G. Knepley 
77487f5d1fdeSMatthew G. Knepley   Not collective
77497f5d1fdeSMatthew G. Knepley 
77507f5d1fdeSMatthew G. Knepley   Input Parameters:
77517f5d1fdeSMatthew G. Knepley + dm - The DM
7752ebd6d717SJed Brown . section - The section describing the layout in v, or NULL to use the default section
7753ebd6d717SJed Brown . globalSection - The section describing the layout in v, or NULL to use the default global section
77547f5d1fdeSMatthew G. Knepley . A - The matrix
7755eaf898f9SPatrick Sanan . point - The point in the DM
77567f5d1fdeSMatthew G. Knepley . values - The array of values
77577f5d1fdeSMatthew G. Knepley - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
77587f5d1fdeSMatthew G. Knepley 
77597f5d1fdeSMatthew G. Knepley   Fortran Notes:
77607f5d1fdeSMatthew G. Knepley   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
77617f5d1fdeSMatthew G. Knepley 
77627f5d1fdeSMatthew G. Knepley   Level: intermediate
77637f5d1fdeSMatthew G. Knepley 
7764db781477SPatrick Sanan .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
77657f5d1fdeSMatthew G. Knepley @*/
7766d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7767d71ae5a4SJacob Faibussowitsch {
7768552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
7769552f7358SJed Brown   PetscInt          *indices;
777071f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
777171f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
7772552f7358SJed Brown   PetscErrorCode     ierr;
7773552f7358SJed Brown 
7774552f7358SJed Brown   PetscFunctionBegin;
7775552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
77769566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
77773dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
77789566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
77793dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
77803dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7781552f7358SJed Brown 
77829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
77830d644c17SKarl Rupp 
77849566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7785d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
77864a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7787552f7358SJed Brown   if (ierr) {
7788552f7358SJed Brown     PetscMPIInt rank;
7789552f7358SJed Brown 
77909566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
77919566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
77929566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
77939566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
77949566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7795c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
7796552f7358SJed Brown   }
77974a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
77984a1e0b3eSMatthew G. Knepley     PetscInt i;
77999566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
780063a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
78019566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
78024a1e0b3eSMatthew G. Knepley   }
780371f0bbf9SMatthew G. Knepley 
78049566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
78059566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
780671f0bbf9SMatthew G. Knepley   PetscFunctionReturn(0);
78074acb8e1eSToby Isaac }
780871f0bbf9SMatthew G. Knepley 
78094a1e0b3eSMatthew G. Knepley /*@C
78104a1e0b3eSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
78114a1e0b3eSMatthew G. Knepley 
78124a1e0b3eSMatthew G. Knepley   Not collective
78134a1e0b3eSMatthew G. Knepley 
78144a1e0b3eSMatthew G. Knepley   Input Parameters:
78154a1e0b3eSMatthew G. Knepley + dmRow - The DM for the row fields
78164a1e0b3eSMatthew G. Knepley . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
78174a1e0b3eSMatthew G. Knepley . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
78184a1e0b3eSMatthew G. Knepley . dmCol - The DM for the column fields
78194a1e0b3eSMatthew G. Knepley . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
78204a1e0b3eSMatthew G. Knepley . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
78214a1e0b3eSMatthew G. Knepley . A - The matrix
78224a1e0b3eSMatthew G. Knepley . point - The point in the DMs
78234a1e0b3eSMatthew G. Knepley . values - The array of values
78244a1e0b3eSMatthew G. Knepley - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
78254a1e0b3eSMatthew G. Knepley 
78264a1e0b3eSMatthew G. Knepley   Level: intermediate
78274a1e0b3eSMatthew G. Knepley 
7828db781477SPatrick Sanan .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
78294a1e0b3eSMatthew G. Knepley @*/
7830d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7831d71ae5a4SJacob Faibussowitsch {
783271f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
783371f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
783471f0bbf9SMatthew G. Knepley   PetscInt           numIndicesRow, numIndicesCol;
783571f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
783671f0bbf9SMatthew G. Knepley   PetscErrorCode     ierr;
783771f0bbf9SMatthew G. Knepley 
783871f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
783971f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
78409566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
784171f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
78429566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
784371f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
784471f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
78459566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
784671f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
78479566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
784871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
784971f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
785071f0bbf9SMatthew G. Knepley 
78519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
78529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
785371f0bbf9SMatthew G. Knepley 
78549566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7855d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
78564a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
785771f0bbf9SMatthew G. Knepley   if (ierr) {
785871f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
785971f0bbf9SMatthew G. Knepley 
78609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
78619566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
78629566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
78639566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
78649566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values));
78659566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7866d3d1a6afSToby Isaac   }
786771f0bbf9SMatthew G. Knepley 
78689566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
78699566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
78709566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7871552f7358SJed Brown   PetscFunctionReturn(0);
7872552f7358SJed Brown }
7873552f7358SJed Brown 
7874d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7875d71ae5a4SJacob Faibussowitsch {
7876de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
7877de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7878de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
7879de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
788017c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7881de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
7882412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
78834ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7884de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
7885de41b84cSMatthew G. Knepley 
7886de41b84cSMatthew G. Knepley   PetscFunctionBegin;
7887de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7888de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
78899566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
7890de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
78919566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
7892de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
78939566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
7894de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
78959566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
7896de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7897de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
78989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
789963a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
79009566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
79019566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
7902de41b84cSMatthew G. Knepley   /* Column indices */
79039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
79044ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
7905de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
7906de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
79079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
7908de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
7909de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7910de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
7911de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
7912de41b84cSMatthew G. Knepley       ++q;
7913de41b84cSMatthew G. Knepley     }
7914de41b84cSMatthew G. Knepley   }
7915de41b84cSMatthew G. Knepley   numCPoints = q;
7916de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
7917de41b84cSMatthew G. Knepley     PetscInt fdof;
7918de41b84cSMatthew G. Knepley 
79199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
79204ca5e9f5SMatthew G. Knepley     if (!dof) continue;
7921de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
79229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
7923de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
7924de41b84cSMatthew G. Knepley     }
7925de41b84cSMatthew G. Knepley     numCIndices += dof;
7926de41b84cSMatthew G. Knepley   }
7927de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
7928de41b84cSMatthew G. Knepley   /* Row indices */
79299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
7930412e9a14SMatthew G. Knepley   {
7931012bc364SMatthew G. Knepley     DMPlexTransform tr;
7932012bc364SMatthew G. Knepley     DMPolytopeType *rct;
7933012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
7934012bc364SMatthew G. Knepley 
79359566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
79369566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
79379566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7938012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
79399566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
7940412e9a14SMatthew G. Knepley   }
79419566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
7942de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
7943de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
79449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
7945de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
79469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
7947de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
7948de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
79499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
79504ca5e9f5SMatthew G. Knepley         if (!dof) continue;
79519371c9d4SSatish Balay         for (s = 0; s < q; ++s)
79529371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
79534ca5e9f5SMatthew G. Knepley         if (s < q) continue;
7954de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
7955de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
7956de41b84cSMatthew G. Knepley         ++q;
7957de41b84cSMatthew G. Knepley       }
7958de41b84cSMatthew G. Knepley     }
79599566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
7960de41b84cSMatthew G. Knepley   }
7961de41b84cSMatthew G. Knepley   numFPoints = q;
7962de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
7963de41b84cSMatthew G. Knepley     PetscInt fdof;
7964de41b84cSMatthew G. Knepley 
79659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
79664ca5e9f5SMatthew G. Knepley     if (!dof) continue;
7967de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
79689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
7969de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
7970de41b84cSMatthew G. Knepley     }
7971de41b84cSMatthew G. Knepley     numFIndices += dof;
7972de41b84cSMatthew G. Knepley   }
7973de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
7974de41b84cSMatthew G. Knepley 
79751dca8a05SBarry 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);
79761dca8a05SBarry 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);
79779566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
79789566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7979de41b84cSMatthew G. Knepley   if (numFields) {
79804acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
79814acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
79824acb8e1eSToby Isaac 
79834acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
79849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
79859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
7986de41b84cSMatthew G. Knepley     }
79874acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
79889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
79899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
79904acb8e1eSToby Isaac     }
79914acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
79929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
79939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
79944acb8e1eSToby Isaac     }
79954acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
79969566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
79979566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
7998de41b84cSMatthew G. Knepley     }
7999de41b84cSMatthew G. Knepley   } else {
80004acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
80014acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
80024acb8e1eSToby Isaac 
80039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
80049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
80054acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
80064acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
80074acb8e1eSToby Isaac 
80089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
80099566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8010de41b84cSMatthew G. Knepley     }
80114acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
80124acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
80134acb8e1eSToby Isaac 
80149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
80159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8016de41b84cSMatthew G. Knepley     }
80179566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
80189566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8019de41b84cSMatthew G. Knepley   }
80209566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
80214acb8e1eSToby Isaac   /* TODO: flips */
8022d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8023de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8024de41b84cSMatthew G. Knepley   if (ierr) {
8025de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8026de41b84cSMatthew G. Knepley 
80279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
80289566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
80299566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
80309566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
80319566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8032de41b84cSMatthew G. Knepley   }
80339566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
80349566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
80359566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
80369566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8037de41b84cSMatthew G. Knepley   PetscFunctionReturn(0);
8038de41b84cSMatthew G. Knepley }
8039de41b84cSMatthew G. Knepley 
8040d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8041d71ae5a4SJacob Faibussowitsch {
80427c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
80437c927364SMatthew G. Knepley   PetscInt       *cpoints = NULL;
80447c927364SMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
804517c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8046412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
80477c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
80487c927364SMatthew G. Knepley 
80497c927364SMatthew G. Knepley   PetscFunctionBegin;
80507c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
80517c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
80529566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
80537c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
80549566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
80557c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
80569566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
80577c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
80589566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
80597c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
80609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
806163a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
80629566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
80639566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
80647c927364SMatthew G. Knepley   /* Column indices */
80659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
80667c927364SMatthew G. Knepley   maxFPoints = numCPoints;
80677c927364SMatthew G. Knepley   /* Compress out points not in the section */
80687c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
80699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
80707c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
80717c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
80727c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
80737c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
80747c927364SMatthew G. Knepley       ++q;
80757c927364SMatthew G. Knepley     }
80767c927364SMatthew G. Knepley   }
80777c927364SMatthew G. Knepley   numCPoints = q;
80787c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
80797c927364SMatthew G. Knepley     PetscInt fdof;
80807c927364SMatthew G. Knepley 
80819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
80827c927364SMatthew G. Knepley     if (!dof) continue;
80837c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
80849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
80857c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
80867c927364SMatthew G. Knepley     }
80877c927364SMatthew G. Knepley     numCIndices += dof;
80887c927364SMatthew G. Knepley   }
80897c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
80907c927364SMatthew G. Knepley   /* Row indices */
80919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8092412e9a14SMatthew G. Knepley   {
8093012bc364SMatthew G. Knepley     DMPlexTransform tr;
8094012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8095012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8096012bc364SMatthew G. Knepley 
80979566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
80989566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
80999566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8100012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
81019566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8102412e9a14SMatthew G. Knepley   }
81039566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
81047c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
81057c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
81069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
81077c927364SMatthew G. Knepley     /* Compress out points not in the section */
81089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
81097c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
81107c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
81119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
81127c927364SMatthew G. Knepley         if (!dof) continue;
81139371c9d4SSatish Balay         for (s = 0; s < q; ++s)
81149371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
81157c927364SMatthew G. Knepley         if (s < q) continue;
81167c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
81177c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
81187c927364SMatthew G. Knepley         ++q;
81197c927364SMatthew G. Knepley       }
81207c927364SMatthew G. Knepley     }
81219566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
81227c927364SMatthew G. Knepley   }
81237c927364SMatthew G. Knepley   numFPoints = q;
81247c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
81257c927364SMatthew G. Knepley     PetscInt fdof;
81267c927364SMatthew G. Knepley 
81279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
81287c927364SMatthew G. Knepley     if (!dof) continue;
81297c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
81309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
81317c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
81327c927364SMatthew G. Knepley     }
81337c927364SMatthew G. Knepley     numFIndices += dof;
81347c927364SMatthew G. Knepley   }
81357c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
81367c927364SMatthew G. Knepley 
81371dca8a05SBarry 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);
81381dca8a05SBarry 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);
81397c927364SMatthew G. Knepley   if (numFields) {
81404acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
81414acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
81424acb8e1eSToby Isaac 
81434acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
81449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
81459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
81467c927364SMatthew G. Knepley     }
81474acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
81489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
81499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
81504acb8e1eSToby Isaac     }
81514acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
81529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
81539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
81544acb8e1eSToby Isaac     }
81554acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
81569566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
81579566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
81587c927364SMatthew G. Knepley     }
81597c927364SMatthew G. Knepley   } else {
81604acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
81614acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
81624acb8e1eSToby Isaac 
81639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
81649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
81654acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
81664acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
81674acb8e1eSToby Isaac 
81689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
81699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
81707c927364SMatthew G. Knepley     }
81714acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
81724acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
81734acb8e1eSToby Isaac 
81749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
81759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
81767c927364SMatthew G. Knepley     }
81779566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
81789566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
81797c927364SMatthew G. Knepley   }
81809566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
81819566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
81827c927364SMatthew G. Knepley   PetscFunctionReturn(0);
81837c927364SMatthew G. Knepley }
81847c927364SMatthew G. Knepley 
81857cd05799SMatthew G. Knepley /*@C
81867cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
81877cd05799SMatthew G. Knepley 
81887cd05799SMatthew G. Knepley   Input Parameter:
81897cd05799SMatthew G. Knepley . dm   - The DMPlex object
81907cd05799SMatthew G. Knepley 
81917cd05799SMatthew G. Knepley   Output Parameter:
81927cd05799SMatthew G. Knepley . cellHeight - The height of a cell
81937cd05799SMatthew G. Knepley 
81947cd05799SMatthew G. Knepley   Level: developer
81957cd05799SMatthew G. Knepley 
8196db781477SPatrick Sanan .seealso `DMPlexSetVTKCellHeight()`
81977cd05799SMatthew G. Knepley @*/
8198d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8199d71ae5a4SJacob Faibussowitsch {
8200552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8201552f7358SJed Brown 
8202552f7358SJed Brown   PetscFunctionBegin;
8203552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8204dadcf809SJacob Faibussowitsch   PetscValidIntPointer(cellHeight, 2);
8205552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
8206552f7358SJed Brown   PetscFunctionReturn(0);
8207552f7358SJed Brown }
8208552f7358SJed Brown 
82097cd05799SMatthew G. Knepley /*@C
82107cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
82117cd05799SMatthew G. Knepley 
82127cd05799SMatthew G. Knepley   Input Parameters:
82137cd05799SMatthew G. Knepley + dm   - The DMPlex object
82147cd05799SMatthew G. Knepley - cellHeight - The height of a cell
82157cd05799SMatthew G. Knepley 
82167cd05799SMatthew G. Knepley   Level: developer
82177cd05799SMatthew G. Knepley 
8218db781477SPatrick Sanan .seealso `DMPlexGetVTKCellHeight()`
82197cd05799SMatthew G. Knepley @*/
8220d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8221d71ae5a4SJacob Faibussowitsch {
8222552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8223552f7358SJed Brown 
8224552f7358SJed Brown   PetscFunctionBegin;
8225552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8226552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
8227552f7358SJed Brown   PetscFunctionReturn(0);
8228552f7358SJed Brown }
8229552f7358SJed Brown 
8230e6139122SMatthew G. Knepley /*@
8231e6139122SMatthew G. Knepley   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
8232e6139122SMatthew G. Knepley 
8233e6139122SMatthew G. Knepley   Input Parameter:
8234e6139122SMatthew G. Knepley . dm - The DMPlex object
8235e6139122SMatthew G. Knepley 
8236e6139122SMatthew G. Knepley   Output Parameters:
82372a9f31c0SMatthew G. Knepley + gcStart - The first ghost cell, or NULL
82382a9f31c0SMatthew G. Knepley - gcEnd   - The upper bound on ghost cells, or NULL
8239e6139122SMatthew G. Knepley 
82402a9f31c0SMatthew G. Knepley   Level: advanced
8241e6139122SMatthew G. Knepley 
8242db781477SPatrick Sanan .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()`
8243e6139122SMatthew G. Knepley @*/
8244d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
8245d71ae5a4SJacob Faibussowitsch {
8246412e9a14SMatthew G. Knepley   DMLabel ctLabel;
8247e6139122SMatthew G. Knepley 
8248e6139122SMatthew G. Knepley   PetscFunctionBegin;
8249e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
82509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
82519566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd));
8252695799ffSMatthew G. Knepley   // Reset label for fast lookup
8253695799ffSMatthew G. Knepley   PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
8254e6139122SMatthew G. Knepley   PetscFunctionReturn(0);
8255e6139122SMatthew G. Knepley }
8256e6139122SMatthew G. Knepley 
8257d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8258d71ae5a4SJacob Faibussowitsch {
8259552f7358SJed Brown   PetscSection section, globalSection;
8260552f7358SJed Brown   PetscInt    *numbers, p;
8261552f7358SJed Brown 
8262552f7358SJed Brown   PetscFunctionBegin;
8263d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
82649566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
82659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
826648a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
82679566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
82689566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
82699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8270552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
82719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8272ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
8273ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
8274552f7358SJed Brown   }
82759566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8276ef48cebcSMatthew G. Knepley   if (globalSize) {
8277ef48cebcSMatthew G. Knepley     PetscLayout layout;
82789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
82799566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
82809566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8281ef48cebcSMatthew G. Knepley   }
82829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
82839566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
8284552f7358SJed Brown   PetscFunctionReturn(0);
8285552f7358SJed Brown }
8286552f7358SJed Brown 
8287d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8288d71ae5a4SJacob Faibussowitsch {
8289412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
8290552f7358SJed Brown 
8291552f7358SJed Brown   PetscFunctionBegin;
82929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
82939566063dSJacob Faibussowitsch   if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
82949566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
82959566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
829681ed3555SMatthew G. Knepley   PetscFunctionReturn(0);
8297552f7358SJed Brown }
829881ed3555SMatthew G. Knepley 
82998dab3259SMatthew G. Knepley /*@
83007cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
83017cd05799SMatthew G. Knepley 
83027cd05799SMatthew G. Knepley   Input Parameter:
83037cd05799SMatthew G. Knepley . dm   - The DMPlex object
83047cd05799SMatthew G. Knepley 
83057cd05799SMatthew G. Knepley   Output Parameter:
83067cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
83077cd05799SMatthew G. Knepley 
83087cd05799SMatthew G. Knepley   Level: developer
83097cd05799SMatthew G. Knepley 
8310db781477SPatrick Sanan .seealso `DMPlexGetVertexNumbering()`
83117cd05799SMatthew G. Knepley @*/
8312d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8313d71ae5a4SJacob Faibussowitsch {
831481ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
831581ed3555SMatthew G. Knepley 
831681ed3555SMatthew G. Knepley   PetscFunctionBegin;
831781ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
83189566063dSJacob Faibussowitsch   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8319552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
8320552f7358SJed Brown   PetscFunctionReturn(0);
8321552f7358SJed Brown }
8322552f7358SJed Brown 
8323d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8324d71ae5a4SJacob Faibussowitsch {
8325412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
832681ed3555SMatthew G. Knepley 
832781ed3555SMatthew G. Knepley   PetscFunctionBegin;
832881ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
83299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
83309566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
833181ed3555SMatthew G. Knepley   PetscFunctionReturn(0);
833281ed3555SMatthew G. Knepley }
833381ed3555SMatthew G. Knepley 
83348dab3259SMatthew G. Knepley /*@
83356aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
83367cd05799SMatthew G. Knepley 
83377cd05799SMatthew G. Knepley   Input Parameter:
83387cd05799SMatthew G. Knepley . dm   - The DMPlex object
83397cd05799SMatthew G. Knepley 
83407cd05799SMatthew G. Knepley   Output Parameter:
83417cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
83427cd05799SMatthew G. Knepley 
83437cd05799SMatthew G. Knepley   Level: developer
83447cd05799SMatthew G. Knepley 
8345db781477SPatrick Sanan .seealso `DMPlexGetCellNumbering()`
83467cd05799SMatthew G. Knepley @*/
8347d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8348d71ae5a4SJacob Faibussowitsch {
8349552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8350552f7358SJed Brown 
8351552f7358SJed Brown   PetscFunctionBegin;
8352552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
83539566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8354552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
8355552f7358SJed Brown   PetscFunctionReturn(0);
8356552f7358SJed Brown }
8357552f7358SJed Brown 
83588dab3259SMatthew G. Knepley /*@
8359966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
8360966484cfSJed Brown 
8361966484cfSJed Brown   Collective on dm
83627cd05799SMatthew G. Knepley 
83637cd05799SMatthew G. Knepley   Input Parameter:
83647cd05799SMatthew G. Knepley . dm   - The DMPlex object
83657cd05799SMatthew G. Knepley 
83667cd05799SMatthew G. Knepley   Output Parameter:
83677cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
83687cd05799SMatthew G. Knepley 
8369966484cfSJed Brown   Notes:
8370966484cfSJed Brown 
8371966484cfSJed Brown   The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
8372966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
8373966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
8374966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
8375966484cfSJed Brown 
8376966484cfSJed Brown   The partitioned mesh is
8377966484cfSJed Brown ```
8378966484cfSJed Brown  (2)--0--(3)--1--(4)    (1)--0--(2)
8379966484cfSJed Brown ```
8380966484cfSJed Brown   and its global numbering is
8381966484cfSJed Brown ```
8382966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
8383966484cfSJed Brown ```
8384966484cfSJed Brown   Then the global numbering is provided as
8385966484cfSJed Brown ```
8386966484cfSJed Brown [0] Number of indices in set 5
8387966484cfSJed Brown [0] 0 0
8388966484cfSJed Brown [0] 1 1
8389966484cfSJed Brown [0] 2 3
8390966484cfSJed Brown [0] 3 4
8391966484cfSJed Brown [0] 4 -6
8392966484cfSJed Brown [1] Number of indices in set 3
8393966484cfSJed Brown [1] 0 2
8394966484cfSJed Brown [1] 1 5
8395966484cfSJed Brown [1] 2 6
8396966484cfSJed Brown ```
8397966484cfSJed Brown 
83987cd05799SMatthew G. Knepley   Level: developer
83997cd05799SMatthew G. Knepley 
8400db781477SPatrick Sanan .seealso `DMPlexGetCellNumbering()`
84017cd05799SMatthew G. Knepley @*/
8402d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8403d71ae5a4SJacob Faibussowitsch {
8404ef48cebcSMatthew G. Knepley   IS        nums[4];
8405862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
8406ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
84070c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
8408ef48cebcSMatthew G. Knepley 
8409ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8410ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
84120c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
84139566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
84140c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
8415862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8416862913ffSStefano Zampini     PetscInt end;
8417862913ffSStefano Zampini 
8418862913ffSStefano Zampini     depths[d] = depth - d;
84199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
84200c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
8421862913ffSStefano Zampini   }
84220c15888dSMatthew G. Knepley   if (empty)
84230c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
84240c15888dSMatthew G. Knepley       depths[d] = -1;
84250c15888dSMatthew G. Knepley       starts[d] = -1;
84260c15888dSMatthew G. Knepley     }
84270c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
84281c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
8429ad540459SPierre 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]);
84300c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
8431ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8432ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8433ef48cebcSMatthew G. Knepley 
84349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
84359566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8436ef48cebcSMatthew G. Knepley     shift += gsize;
8437ef48cebcSMatthew G. Knepley   }
84389566063dSJacob Faibussowitsch   PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers));
84399566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
8440ef48cebcSMatthew G. Knepley   PetscFunctionReturn(0);
8441ef48cebcSMatthew G. Knepley }
8442ef48cebcSMatthew G. Knepley 
844308a22f4bSMatthew G. Knepley /*@
844408a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
844508a22f4bSMatthew G. Knepley 
844608a22f4bSMatthew G. Knepley   Input Parameter:
844708a22f4bSMatthew G. Knepley . dm - The DMPlex object
844808a22f4bSMatthew G. Knepley 
844908a22f4bSMatthew G. Knepley   Output Parameter:
845008a22f4bSMatthew G. Knepley . ranks - The rank field
845108a22f4bSMatthew G. Knepley 
845208a22f4bSMatthew G. Knepley   Options Database Keys:
845308a22f4bSMatthew G. Knepley . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
845408a22f4bSMatthew G. Knepley 
845508a22f4bSMatthew G. Knepley   Level: intermediate
845608a22f4bSMatthew G. Knepley 
8457db781477SPatrick Sanan .seealso: `DMView()`
845808a22f4bSMatthew G. Knepley @*/
8459d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8460d71ae5a4SJacob Faibussowitsch {
846108a22f4bSMatthew G. Knepley   DM             rdm;
846208a22f4bSMatthew G. Knepley   PetscFE        fe;
846308a22f4bSMatthew G. Knepley   PetscScalar   *r;
846408a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
8465a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
846608a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
8467a55f9a55SMatthew G. Knepley   PetscBool      simplex;
846808a22f4bSMatthew G. Knepley 
846908a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
8470f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8471f95ace6aSMatthew G. Knepley   PetscValidPointer(ranks, 2);
84729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
84739566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
84749566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
84759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
84769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8477a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
84789566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
84799566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
84809566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
84819566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
84829566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
84839566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
84849566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
84859566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
848608a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
848708a22f4bSMatthew G. Knepley     PetscScalar *lr;
848808a22f4bSMatthew G. Knepley 
84899566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
849071f09efeSPierre Jolivet     if (lr) *lr = rank;
849108a22f4bSMatthew G. Knepley   }
84929566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
84939566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
849408a22f4bSMatthew G. Knepley   PetscFunctionReturn(0);
849508a22f4bSMatthew G. Knepley }
849608a22f4bSMatthew G. Knepley 
8497ca8062c8SMatthew G. Knepley /*@
849818e14f0cSMatthew G. Knepley   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
849918e14f0cSMatthew G. Knepley 
850018e14f0cSMatthew G. Knepley   Input Parameters:
850118e14f0cSMatthew G. Knepley + dm    - The DMPlex
850218e14f0cSMatthew G. Knepley - label - The DMLabel
850318e14f0cSMatthew G. Knepley 
850418e14f0cSMatthew G. Knepley   Output Parameter:
850518e14f0cSMatthew G. Knepley . val - The label value field
850618e14f0cSMatthew G. Knepley 
850718e14f0cSMatthew G. Knepley   Options Database Keys:
850818e14f0cSMatthew G. Knepley . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
850918e14f0cSMatthew G. Knepley 
851018e14f0cSMatthew G. Knepley   Level: intermediate
851118e14f0cSMatthew G. Knepley 
8512db781477SPatrick Sanan .seealso: `DMView()`
851318e14f0cSMatthew G. Knepley @*/
8514d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8515d71ae5a4SJacob Faibussowitsch {
851618e14f0cSMatthew G. Knepley   DM           rdm;
851718e14f0cSMatthew G. Knepley   PetscFE      fe;
851818e14f0cSMatthew G. Knepley   PetscScalar *v;
851918e14f0cSMatthew G. Knepley   PetscInt     dim, cStart, cEnd, c;
852018e14f0cSMatthew G. Knepley 
852118e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
852218e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
852318e14f0cSMatthew G. Knepley   PetscValidPointer(label, 2);
852418e14f0cSMatthew G. Knepley   PetscValidPointer(val, 3);
85259566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
85269566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
85279566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
85289566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "label_value"));
85299566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
85309566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
85319566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
85329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
85339566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
85349566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*val, "label_value"));
85359566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*val, &v));
853618e14f0cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
853718e14f0cSMatthew G. Knepley     PetscScalar *lv;
853818e14f0cSMatthew G. Knepley     PetscInt     cval;
853918e14f0cSMatthew G. Knepley 
85409566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv));
85419566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, c, &cval));
854218e14f0cSMatthew G. Knepley     *lv = cval;
854318e14f0cSMatthew G. Knepley   }
85449566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*val, &v));
85459566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
854618e14f0cSMatthew G. Knepley   PetscFunctionReturn(0);
854718e14f0cSMatthew G. Knepley }
854818e14f0cSMatthew G. Knepley 
854918e14f0cSMatthew G. Knepley /*@
8550ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8551ca8062c8SMatthew G. Knepley 
855269916449SMatthew G. Knepley   Input Parameter:
855369916449SMatthew G. Knepley . dm - The DMPlex object
8554ca8062c8SMatthew G. Knepley 
855595eb5ee5SVaclav Hapla   Notes:
855695eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
855795eb5ee5SVaclav Hapla 
855895eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8559ca8062c8SMatthew G. Knepley 
8560ca8062c8SMatthew G. Knepley   Level: developer
8561ca8062c8SMatthew G. Knepley 
8562db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8563ca8062c8SMatthew G. Knepley @*/
8564d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
8565d71ae5a4SJacob Faibussowitsch {
8566ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
8567ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
8568ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
856957beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
857057beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
8571ca8062c8SMatthew G. Knepley 
8572ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8573ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
85749566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
85759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
85769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
8577ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
85789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8579ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
85809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
85819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
8582ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
858342e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
858442e66dfaSMatthew G. Knepley       PetscInt  d;
858542e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
85869371c9d4SSatish Balay         if (cone[c] == cone[d]) {
85879371c9d4SSatish Balay           dup = PETSC_TRUE;
85889371c9d4SSatish Balay           break;
85899371c9d4SSatish Balay         }
859042e66dfaSMatthew G. Knepley       }
85919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
85929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
8593ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
8594ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
8595ca8062c8SMatthew G. Knepley       }
859642e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
859763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
859848a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
85999566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
860063a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
860148a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
86029566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
860363a3b9bcSJacob 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]);
8604f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
8605ca8062c8SMatthew G. Knepley       }
860642e66dfaSMatthew G. Knepley     }
86079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
86089371c9d4SSatish Balay     if (p != pp) {
86099371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
86109371c9d4SSatish Balay       continue;
86119371c9d4SSatish Balay     }
86129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
86139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
8614ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
86159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
86169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
8617ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
86189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
86199371c9d4SSatish Balay         if (cone[c] != pp) {
86209371c9d4SSatish Balay           c = 0;
86219371c9d4SSatish Balay           break;
86229371c9d4SSatish Balay         }
8623ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
8624ca8062c8SMatthew G. Knepley       }
8625ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
862663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
862748a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
86289566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
862963a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
863048a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
86319566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
863263a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
8633ca8062c8SMatthew G. Knepley       }
8634ca8062c8SMatthew G. Knepley     }
8635ca8062c8SMatthew G. Knepley   }
863657beb4faSStefano Zampini   if (storagecheck) {
86379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
86389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
863963a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
864057beb4faSStefano Zampini   }
8641ca8062c8SMatthew G. Knepley   PetscFunctionReturn(0);
8642ca8062c8SMatthew G. Knepley }
8643ca8062c8SMatthew G. Knepley 
8644412e9a14SMatthew G. Knepley /*
8645412e9a14SMatthew 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.
8646412e9a14SMatthew G. Knepley */
8647d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8648d71ae5a4SJacob Faibussowitsch {
8649412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
8650412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
8651412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
8652412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8653412e9a14SMatthew G. Knepley 
8654412e9a14SMatthew G. Knepley   PetscFunctionBegin;
8655412e9a14SMatthew G. Knepley   *unsplit = 0;
8656412e9a14SMatthew G. Knepley   switch (ct) {
8657d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
8658d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
8659d71ae5a4SJacob Faibussowitsch     break;
8660412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
86619566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
86629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8663412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
86649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
8665412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8666412e9a14SMatthew G. Knepley     }
8667412e9a14SMatthew G. Knepley     break;
8668412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
8669412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
86709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
86719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8672412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
86739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
86749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
8675412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
86769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
8677412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8678412e9a14SMatthew G. Knepley           PetscInt p;
86799371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
86809371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
8681412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
8682412e9a14SMatthew G. Knepley         }
8683412e9a14SMatthew G. Knepley       }
8684412e9a14SMatthew G. Knepley     }
8685412e9a14SMatthew G. Knepley     break;
8686d71ae5a4SJacob Faibussowitsch   default:
8687d71ae5a4SJacob Faibussowitsch     break;
8688412e9a14SMatthew G. Knepley   }
8689412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
86909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
8691412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8692412e9a14SMatthew G. Knepley   }
8693412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
8694412e9a14SMatthew G. Knepley }
8695412e9a14SMatthew G. Knepley 
8696ca8062c8SMatthew G. Knepley /*@
8697ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8698ca8062c8SMatthew G. Knepley 
8699ca8062c8SMatthew G. Knepley   Input Parameters:
8700ca8062c8SMatthew G. Knepley + dm - The DMPlex object
870158723a97SMatthew G. Knepley - cellHeight - Normally 0
8702ca8062c8SMatthew G. Knepley 
870395eb5ee5SVaclav Hapla   Notes:
870495eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
870525c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
8706ca8062c8SMatthew G. Knepley 
870795eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
870895eb5ee5SVaclav Hapla 
8709ca8062c8SMatthew G. Knepley   Level: developer
8710ca8062c8SMatthew G. Knepley 
8711db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8712ca8062c8SMatthew G. Knepley @*/
8713d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8714d71ae5a4SJacob Faibussowitsch {
8715412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
8716412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
8717412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
8718ca8062c8SMatthew G. Knepley 
8719ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8720ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87219566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
87229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
87239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8724412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8725412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
8726412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
872758723a97SMatthew G. Knepley 
87289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
872963a3b9bcSJacob Faibussowitsch     PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c);
8730412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8731412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
87329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
873363a3b9bcSJacob 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));
8734412e9a14SMatthew G. Knepley     }
87359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
873658723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
873758723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
8738412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
873958723a97SMatthew G. Knepley     }
87409566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8741412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
8742412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8743412e9a14SMatthew G. Knepley       PetscInt unsplit;
874442363296SMatthew G. Knepley 
87459566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8746412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
874742363296SMatthew G. Knepley     }
874863a3b9bcSJacob 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));
874942363296SMatthew G. Knepley   }
8750ca8062c8SMatthew G. Knepley   PetscFunctionReturn(0);
8751ca8062c8SMatthew G. Knepley }
87529bf0dad6SMatthew G. Knepley 
87539bf0dad6SMatthew G. Knepley /*@
87549bf0dad6SMatthew 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
87559bf0dad6SMatthew G. Knepley 
87568f6815adSVaclav Hapla   Collective
8757899ea2b8SJacob Faibussowitsch 
87589bf0dad6SMatthew G. Knepley   Input Parameters:
87599bf0dad6SMatthew G. Knepley + dm - The DMPlex object
87609bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
87619bf0dad6SMatthew G. Knepley 
876245da879fSVaclav Hapla   Notes:
876345da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
876445da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
876545da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
876645da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
87679bf0dad6SMatthew G. Knepley 
876895eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
876995eb5ee5SVaclav Hapla 
87709bf0dad6SMatthew G. Knepley   Level: developer
87719bf0dad6SMatthew G. Knepley 
8772db781477SPatrick Sanan .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
87739bf0dad6SMatthew G. Knepley @*/
8774d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8775d71ae5a4SJacob Faibussowitsch {
8776ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8777899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
87789bf0dad6SMatthew G. Knepley 
87799bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
87809bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87818f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
878245da879fSVaclav Hapla   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
87838f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
87848f6815adSVaclav Hapla     PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported");
87858f6815adSVaclav Hapla     PetscFunctionReturn(0);
8786899ea2b8SJacob Faibussowitsch   }
8787899ea2b8SJacob Faibussowitsch 
87889566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
87899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
87909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8791ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
87929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
87933554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
8794412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
8795412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
8796ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
8797412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
8798412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
87999bf0dad6SMatthew G. Knepley 
88009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
88019566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8802412e9a14SMatthew G. Knepley       if (unsplit) continue;
88039566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
88049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
88059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
88069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
88079bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
88089bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
88099bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
88109bf0dad6SMatthew G. Knepley       }
88119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
881263a3b9bcSJacob 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);
88139bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
8814d4961f80SStefano Zampini         DMPolytopeType fct;
88159bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
88169bf0dad6SMatthew G. Knepley 
88179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
88189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
88199bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
88209bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
88219bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
88229bf0dad6SMatthew G. Knepley         }
882363a3b9bcSJacob 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]);
88249bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
8825b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
8826b5a892a1SMatthew G. Knepley             PetscInt v1;
8827b5a892a1SMatthew G. Knepley 
88289566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
882963a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
88309566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
883163a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
88329566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
883363a3b9bcSJacob 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]);
8834b5a892a1SMatthew G. Knepley           }
88359bf0dad6SMatthew G. Knepley         }
88369566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
8837412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
88389bf0dad6SMatthew G. Knepley       }
88399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
88409566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
88419bf0dad6SMatthew G. Knepley     }
88423554e41dSMatthew G. Knepley   }
8843552f7358SJed Brown   PetscFunctionReturn(0);
8844552f7358SJed Brown }
88453913d7c8SMatthew G. Knepley 
8846bb6a34a8SMatthew G. Knepley /*@
8847bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
8848bb6a34a8SMatthew G. Knepley 
8849bb6a34a8SMatthew G. Knepley   Input Parameter:
8850bb6a34a8SMatthew G. Knepley . dm - The DMPlex object
8851bb6a34a8SMatthew G. Knepley 
885295eb5ee5SVaclav Hapla   Notes:
885395eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
885495eb5ee5SVaclav Hapla 
885595eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8856bb6a34a8SMatthew G. Knepley 
8857bb6a34a8SMatthew G. Knepley   Level: developer
8858bb6a34a8SMatthew G. Knepley 
8859db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8860bb6a34a8SMatthew G. Knepley @*/
8861d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
8862d71ae5a4SJacob Faibussowitsch {
8863a2a9e04cSMatthew G. Knepley   Vec       coordinates;
8864bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
8865bb6a34a8SMatthew G. Knepley   PetscReal vol;
886651a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
8867bb6a34a8SMatthew G. Knepley 
8868bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
88699566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
88709566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
887151a74b61SMatthew G. Knepley   if (dim != dE) PetscFunctionReturn(0);
88729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8873bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
88749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8875a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
88769566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8877412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8878412e9a14SMatthew G. Knepley     DMPolytopeType ct;
8879412e9a14SMatthew G. Knepley     PetscInt       unsplit;
8880412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
8881412e9a14SMatthew G. Knepley 
88829566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
8883412e9a14SMatthew G. Knepley     switch (ct) {
8884412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8885412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8886d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8887d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
8888d71ae5a4SJacob Faibussowitsch       break;
8889d71ae5a4SJacob Faibussowitsch     default:
8890d71ae5a4SJacob Faibussowitsch       break;
8891412e9a14SMatthew G. Knepley     }
8892412e9a14SMatthew G. Knepley     switch (ct) {
8893412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
8894412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8895412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8896d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
8897d71ae5a4SJacob Faibussowitsch       continue;
8898d71ae5a4SJacob Faibussowitsch     default:
8899d71ae5a4SJacob Faibussowitsch       break;
8900412e9a14SMatthew G. Knepley     }
89019566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8902412e9a14SMatthew G. Knepley     if (unsplit) continue;
89039566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
89041dca8a05SBarry 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);
890563a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
89066858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
89076858538eSMatthew G. Knepley     if (depth > 1) {
89089566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
89091dca8a05SBarry 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);
891063a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
8911bb6a34a8SMatthew G. Knepley     }
8912bb6a34a8SMatthew G. Knepley   }
8913bb6a34a8SMatthew G. Knepley   PetscFunctionReturn(0);
8914bb6a34a8SMatthew G. Knepley }
8915bb6a34a8SMatthew G. Knepley 
891603da9461SVaclav Hapla /*@
89177726db96SVaclav Hapla   DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex.
89187726db96SVaclav Hapla 
89197726db96SVaclav Hapla   Collective
892003da9461SVaclav Hapla 
892103da9461SVaclav Hapla   Input Parameters:
89227726db96SVaclav Hapla + dm - The DMPlex object
8923d7d32a9aSMatthew G. Knepley . pointSF - The Point SF, or NULL for Point SF attached to DM
8924d7d32a9aSMatthew G. Knepley - allowExtraRoots - Flag to allow extra points not present in the DM
892503da9461SVaclav Hapla 
8926e83a0d2dSVaclav Hapla   Notes:
8927e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
892803da9461SVaclav Hapla 
892995eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
893095eb5ee5SVaclav Hapla 
8931d7d32a9aSMatthew G. Knepley   Extra roots can come from priodic cuts, where additional points appear on the boundary
8932d7d32a9aSMatthew G. Knepley 
893303da9461SVaclav Hapla   Level: developer
893403da9461SVaclav Hapla 
8935db781477SPatrick Sanan .seealso: `DMGetPointSF()`, `DMSetFromOptions()`
893603da9461SVaclav Hapla @*/
8937d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
8938d71ae5a4SJacob Faibussowitsch {
89397726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
89407726db96SVaclav Hapla   const PetscInt    *locals;
89417726db96SVaclav Hapla   const PetscSFNode *remotes;
8942f0cfc026SVaclav Hapla   PetscBool          distributed;
89437726db96SVaclav Hapla   MPI_Comm           comm;
89447726db96SVaclav Hapla   PetscMPIInt        rank;
894503da9461SVaclav Hapla 
894603da9461SVaclav Hapla   PetscFunctionBegin;
894703da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89487726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
89497726db96SVaclav Hapla   else pointSF = dm->sf;
89507726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
89517726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
89527726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
89537726db96SVaclav Hapla   {
89547726db96SVaclav Hapla     PetscMPIInt mpiFlag;
89557726db96SVaclav Hapla 
89567726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
89577726db96SVaclav 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);
89587726db96SVaclav Hapla   }
89597726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
89609566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
89617726db96SVaclav Hapla   if (!distributed) {
89627726db96SVaclav 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);
89638918e3e2SVaclav Hapla     PetscFunctionReturn(0);
89648918e3e2SVaclav Hapla   }
89657726db96SVaclav 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);
89667726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
896703da9461SVaclav Hapla 
89687726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
89697726db96SVaclav Hapla   {
89707726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
89717726db96SVaclav Hapla 
89727726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
89737726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
8974d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
89757726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
89767726db96SVaclav Hapla   }
89777726db96SVaclav Hapla 
89787726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
89797726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
89807726db96SVaclav 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);
89817726db96SVaclav Hapla   }
89827726db96SVaclav Hapla 
89837726db96SVaclav Hapla   /* Check there are no cells in interface */
89847726db96SVaclav Hapla   if (!overlap) {
89857726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
89867726db96SVaclav Hapla 
89879566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
89889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8989f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
89907726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
8991f5869d18SMatthew G. Knepley 
89927726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
89937726db96SVaclav Hapla     }
899403da9461SVaclav Hapla   }
8995ece87651SVaclav Hapla 
89967726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
89977726db96SVaclav Hapla   {
89987726db96SVaclav Hapla     const PetscInt *rootdegree;
89997726db96SVaclav Hapla 
90007726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
90017726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9002f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
90037726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9004f5869d18SMatthew G. Knepley       const PetscInt *cone;
9005f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9006f5869d18SMatthew G. Knepley 
90079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
90089566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9009f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9010f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
90117726db96SVaclav Hapla           if (locals) {
90129566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
90137726db96SVaclav Hapla           } else {
90147726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
90157726db96SVaclav Hapla           }
901663a3b9bcSJacob 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]);
9017f5869d18SMatthew G. Knepley         }
9018f5869d18SMatthew G. Knepley       }
9019ece87651SVaclav Hapla     }
90207726db96SVaclav Hapla   }
902103da9461SVaclav Hapla   PetscFunctionReturn(0);
902203da9461SVaclav Hapla }
902303da9461SVaclav Hapla 
90247f9d8d6cSVaclav Hapla /*@
90257f9d8d6cSVaclav Hapla   DMPlexCheck - Perform various checks of Plex sanity
90267f9d8d6cSVaclav Hapla 
90277f9d8d6cSVaclav Hapla   Input Parameter:
90287f9d8d6cSVaclav Hapla . dm - The DMPlex object
90297f9d8d6cSVaclav Hapla 
90307f9d8d6cSVaclav Hapla   Notes:
90317f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
90327f9d8d6cSVaclav Hapla 
90337f9d8d6cSVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
90347f9d8d6cSVaclav Hapla 
90357f9d8d6cSVaclav Hapla   Currently does not include DMPlexCheckCellShape().
90367f9d8d6cSVaclav Hapla 
90377f9d8d6cSVaclav Hapla   Level: developer
90387f9d8d6cSVaclav Hapla 
90397f9d8d6cSVaclav Hapla .seealso: DMCreate(), DMSetFromOptions()
90407f9d8d6cSVaclav Hapla @*/
9041d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9042d71ae5a4SJacob Faibussowitsch {
90437f9d8d6cSVaclav Hapla   PetscInt cellHeight;
90447f9d8d6cSVaclav Hapla 
9045b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
90467f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
90479566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
90489566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
90499566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
90509566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9051d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
90529566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
9053b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
9054b5a892a1SMatthew G. Knepley }
9055b5a892a1SMatthew G. Knepley 
90569371c9d4SSatish Balay typedef struct cell_stats {
9057068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9058068a5610SStefano Zampini   PetscInt  count;
9059068a5610SStefano Zampini } cell_stats_t;
9060068a5610SStefano Zampini 
9061d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9062d71ae5a4SJacob Faibussowitsch {
9063068a5610SStefano Zampini   PetscInt i, N = *len;
9064068a5610SStefano Zampini 
9065068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9066068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9067068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9068068a5610SStefano Zampini 
9069068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9070068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9071068a5610SStefano Zampini     B->sum += A->sum;
9072068a5610SStefano Zampini     B->squaresum += A->squaresum;
9073068a5610SStefano Zampini     B->count += A->count;
9074068a5610SStefano Zampini   }
9075068a5610SStefano Zampini }
9076068a5610SStefano Zampini 
9077068a5610SStefano Zampini /*@
907843fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9079068a5610SStefano Zampini 
90808261a58bSMatthew G. Knepley   Collective on dm
90818261a58bSMatthew G. Knepley 
9082068a5610SStefano Zampini   Input Parameters:
9083068a5610SStefano Zampini + dm        - The DMPlex object
908443fa8764SMatthew G. Knepley . output    - If true, statistics will be displayed on stdout
908543fa8764SMatthew G. Knepley - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
9086068a5610SStefano Zampini 
908795eb5ee5SVaclav Hapla   Notes:
908895eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
908995eb5ee5SVaclav Hapla 
909095eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
9091068a5610SStefano Zampini 
9092068a5610SStefano Zampini   Level: developer
9093068a5610SStefano Zampini 
9094db781477SPatrick Sanan .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9095068a5610SStefano Zampini @*/
9096d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9097d71ae5a4SJacob Faibussowitsch {
9098068a5610SStefano Zampini   DM           dmCoarse;
909943fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
910043fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
910143fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
910243fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9103412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
910443fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9105068a5610SStefano Zampini 
9106068a5610SStefano Zampini   PetscFunctionBegin;
9107068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9108068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9109068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9110068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9111068a5610SStefano Zampini   stats.count                 = 0;
9112068a5610SStefano Zampini 
91139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
91149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
91159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
91169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
91179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
91189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9119412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9120068a5610SStefano Zampini     PetscInt  i;
9121068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9122068a5610SStefano Zampini 
91239566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
912463a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
912543fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9126068a5610SStefano Zampini       frobJ += J[i] * J[i];
9127068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9128068a5610SStefano Zampini     }
9129068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9130068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9131068a5610SStefano Zampini 
9132068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9133068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9134068a5610SStefano Zampini     stats.sum += cond;
9135068a5610SStefano Zampini     stats.squaresum += cond2;
9136068a5610SStefano Zampini     stats.count++;
91378261a58bSMatthew G. Knepley     if (output && cond > limit) {
913843fa8764SMatthew G. Knepley       PetscSection coordSection;
913943fa8764SMatthew G. Knepley       Vec          coordsLocal;
914043fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
914143fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
914243fa8764SMatthew G. Knepley 
91439566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
91449566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
91459566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
914663a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
914743fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
914863a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
914943fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
91509566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
91519566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
915243fa8764SMatthew G. Knepley         }
91539566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
915443fa8764SMatthew G. Knepley       }
91559566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
915643fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
915743fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
915843fa8764SMatthew G. Knepley 
915943fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
916043fa8764SMatthew G. Knepley           PetscReal len;
916143fa8764SMatthew G. Knepley 
91629566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
916363a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
916443fa8764SMatthew G. Knepley         }
916543fa8764SMatthew G. Knepley       }
91669566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
91679566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
916843fa8764SMatthew G. Knepley     }
9169068a5610SStefano Zampini   }
91709566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9171068a5610SStefano Zampini 
9172068a5610SStefano Zampini   if (size > 1) {
9173068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9174068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9175068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9176068a5610SStefano Zampini     MPI_Op       statReduce;
9177068a5610SStefano Zampini 
91789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
91799566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
91809566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
91819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
91829566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
91839566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
9184068a5610SStefano Zampini   } else {
91859566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
9186068a5610SStefano Zampini   }
9187dd400576SPatrick Sanan   if (rank == 0) {
9188068a5610SStefano Zampini     count = globalStats.count;
9189068a5610SStefano Zampini     min   = globalStats.min;
9190068a5610SStefano Zampini     max   = globalStats.max;
9191068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
9192068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
9193068a5610SStefano Zampini   }
9194068a5610SStefano Zampini 
919548a46eb9SPierre 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));
91969566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
9197068a5610SStefano Zampini 
91989566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
9199068a5610SStefano Zampini   if (dmCoarse) {
9200068a5610SStefano Zampini     PetscBool isplex;
9201068a5610SStefano Zampini 
92029566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
92031baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
9204068a5610SStefano Zampini   }
9205068a5610SStefano Zampini   PetscFunctionReturn(0);
9206068a5610SStefano Zampini }
9207068a5610SStefano Zampini 
9208f108dbd7SJacob Faibussowitsch /*@
9209f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
9210f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
9211f108dbd7SJacob Faibussowitsch 
92126ed19f2fSJacob Faibussowitsch   Collective on dm
9213f108dbd7SJacob Faibussowitsch 
9214f108dbd7SJacob Faibussowitsch   Input Parameters:
9215f108dbd7SJacob Faibussowitsch + dm   - The DMPlex object
9216f108dbd7SJacob Faibussowitsch . fv   - Optional PetscFV object for pre-computed cell/face centroid information
9217f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
9218f108dbd7SJacob Faibussowitsch 
9219f108dbd7SJacob Faibussowitsch   Output Parameters:
9220f108dbd7SJacob Faibussowitsch + OrthQual      - Vec containing orthogonal quality per cell
9221f108dbd7SJacob Faibussowitsch - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
9222f108dbd7SJacob Faibussowitsch 
9223f108dbd7SJacob Faibussowitsch   Options Database Keys:
9224f108dbd7SJacob Faibussowitsch + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
9225f108dbd7SJacob Faibussowitsch supported.
9226f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
9227f108dbd7SJacob Faibussowitsch 
9228f108dbd7SJacob Faibussowitsch   Notes:
9229f108dbd7SJacob Faibussowitsch   Orthogonal quality is given by the following formula:
9230f108dbd7SJacob Faibussowitsch 
9231f108dbd7SJacob Faibussowitsch   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
9232f108dbd7SJacob Faibussowitsch 
9233f108dbd7SJacob 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
9234f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
9235f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
9236f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
9237f108dbd7SJacob Faibussowitsch 
9238f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
9239f108dbd7SJacob Faibussowitsch 
9240f108dbd7SJacob Faibussowitsch   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
9241f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
9242f108dbd7SJacob Faibussowitsch 
9243f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
9244f108dbd7SJacob Faibussowitsch 
9245f108dbd7SJacob Faibussowitsch   Level: intermediate
9246f108dbd7SJacob Faibussowitsch 
9247db781477SPatrick Sanan .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()`
9248f108dbd7SJacob Faibussowitsch @*/
9249d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
9250d71ae5a4SJacob Faibussowitsch {
92516ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
92526ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
92536ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
9254f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
92556ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
9256f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
9257f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
9258f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
9259f108dbd7SJacob Faibussowitsch   IS                     glob;
9260f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
9261f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
9262f108dbd7SJacob Faibussowitsch 
9263f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
9264f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9265ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
9266f108dbd7SJacob Faibussowitsch   PetscValidPointer(OrthQual, 4);
92676bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
92689566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
92699566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
927063a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
92716ed19f2fSJacob Faibussowitsch   {
92726ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
92736ed19f2fSJacob Faibussowitsch 
92749566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
9275f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
9276f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
9277f108dbd7SJacob Faibussowitsch 
92789566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
927998921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
9280f108dbd7SJacob Faibussowitsch     }
92816ed19f2fSJacob Faibussowitsch   }
9282f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
9283f108dbd7SJacob Faibussowitsch     PetscValidPointer(OrthQualLabel, 5);
92849566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
92859566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
92869371c9d4SSatish Balay   } else {
92879371c9d4SSatish Balay     *OrthQualLabel = NULL;
92889371c9d4SSatish Balay   }
92899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
92909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
92919566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
92929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
92939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
92949566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
92959566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
92969566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
92979566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
92989566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
92999566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
93009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
93019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
93029566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
93039566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
93049566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
93059566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
93069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
93076ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
93086ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9309f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
9310f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
9311898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
9312f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
9313f108dbd7SJacob Faibussowitsch 
93146ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
9315f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
9316f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
93179566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
93189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9319f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
93209566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
93216ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
93226ed19f2fSJacob Faibussowitsch       PetscInt         i;
93236ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
9324f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9325f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
9326f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
9327f108dbd7SJacob Faibussowitsch 
9328f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9329f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
93309566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9331f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
93326ed19f2fSJacob Faibussowitsch       {
93336ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
93346ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
93356ed19f2fSJacob Faibussowitsch 
93369566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
93379566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
93389566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
93396ed19f2fSJacob Faibussowitsch       }
9340f108dbd7SJacob Faibussowitsch 
9341f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9342f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9343f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9344f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9345f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9346addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9347addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9348addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9349f108dbd7SJacob Faibussowitsch       }
9350addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9351addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9352addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9353f108dbd7SJacob Faibussowitsch 
9354f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9355f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9356f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
9357f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
9358f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
9359f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9360f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
9361f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
9362f108dbd7SJacob Faibussowitsch       }
9363ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
9364ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
9365f108dbd7SJacob Faibussowitsch     }
93669566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
93679566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9368f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
93696ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9370f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
93719566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9372f108dbd7SJacob Faibussowitsch     }
9373f108dbd7SJacob Faibussowitsch   }
93749566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
93759566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
93769566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
93779566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
93789566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
93799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9380f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
93819566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9382f108dbd7SJacob Faibussowitsch   }
93839566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
93849566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&vwr));
93859566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
9386f108dbd7SJacob Faibussowitsch   PetscFunctionReturn(0);
9387f108dbd7SJacob Faibussowitsch }
9388f108dbd7SJacob Faibussowitsch 
93891eb70e55SToby Isaac /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
93901eb70e55SToby Isaac  * interpolator construction */
9391d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9392d71ae5a4SJacob Faibussowitsch {
93931eb70e55SToby Isaac   PetscSection section, newSection, gsection;
93941eb70e55SToby Isaac   PetscSF      sf;
93951eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
93961eb70e55SToby Isaac 
93971eb70e55SToby Isaac   PetscFunctionBegin;
93981eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93991eb70e55SToby Isaac   PetscValidPointer(odm, 2);
94009566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
94019566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
94029566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
94031eb70e55SToby Isaac   if (!ghasConstraints) {
94049566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
94051eb70e55SToby Isaac     *odm = dm;
94061eb70e55SToby Isaac     PetscFunctionReturn(0);
94071eb70e55SToby Isaac   }
94089566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
94099566063dSJacob Faibussowitsch   PetscCall(DMCopyFields(dm, *odm));
94109566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
94119566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
94129566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
94139566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
94149566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
94151eb70e55SToby Isaac   PetscFunctionReturn(0);
94161eb70e55SToby Isaac }
94171eb70e55SToby Isaac 
9418d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9419d71ae5a4SJacob Faibussowitsch {
94201eb70e55SToby Isaac   DM        dmco, dmfo;
94211eb70e55SToby Isaac   Mat       interpo;
94221eb70e55SToby Isaac   Vec       rscale;
94231eb70e55SToby Isaac   Vec       cglobalo, clocal;
94241eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
94251eb70e55SToby Isaac   PetscBool regular;
94261eb70e55SToby Isaac 
94271eb70e55SToby Isaac   PetscFunctionBegin;
94289566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
94299566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
94309566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
94319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
94329566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
94339566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
94349566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
94359566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
94369566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
94379566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
94389566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
94399566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
94409566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
94419566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
94429566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
94439566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
94449566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
94459566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
94469566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
94479566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
94489566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
94499566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
94509566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
94519566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
94521eb70e55SToby Isaac   *shift = fglobal;
94539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
94549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
94559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
94569566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
94579566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
94589566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
94599566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
94609566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
94611eb70e55SToby Isaac   PetscFunctionReturn(0);
94621eb70e55SToby Isaac }
94631eb70e55SToby Isaac 
9464d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9465d71ae5a4SJacob Faibussowitsch {
94661eb70e55SToby Isaac   PetscObject shifto;
94671eb70e55SToby Isaac   Vec         shift;
94681eb70e55SToby Isaac 
94691eb70e55SToby Isaac   PetscFunctionBegin;
94701eb70e55SToby Isaac   if (!interp) {
94711eb70e55SToby Isaac     Vec rscale;
94721eb70e55SToby Isaac 
94739566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
94749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
94751eb70e55SToby Isaac   } else {
94769566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
94771eb70e55SToby Isaac   }
94789566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
94791eb70e55SToby Isaac   if (!shifto) {
94809566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
94819566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
94821eb70e55SToby Isaac     shifto = (PetscObject)shift;
94839566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
94841eb70e55SToby Isaac   }
94851eb70e55SToby Isaac   shift = (Vec)shifto;
94869566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
94879566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
94889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
94891eb70e55SToby Isaac   PetscFunctionReturn(0);
94901eb70e55SToby Isaac }
94911eb70e55SToby Isaac 
9492bceba477SMatthew G. Knepley /* Pointwise interpolation
9493bceba477SMatthew G. Knepley      Just code FEM for now
9494bceba477SMatthew G. Knepley      u^f = I u^c
94954ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
94964ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
94974ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
9498bceba477SMatthew G. Knepley */
9499d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9500d71ae5a4SJacob Faibussowitsch {
9501bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
9502bceba477SMatthew G. Knepley   PetscInt     m, n;
9503a063dac3SMatthew G. Knepley   void        *ctx;
950468132eb9SMatthew G. Knepley   DM           cdm;
9505cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9506bceba477SMatthew G. Knepley 
9507bceba477SMatthew G. Knepley   PetscFunctionBegin;
95089566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
95099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
95109566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
95119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
951268132eb9SMatthew G. Knepley 
95139566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
95149566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
95159566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
95169566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
95179566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
951868132eb9SMatthew G. Knepley 
95199566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
95209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
95219566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
95229566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
95239566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
95244db47ee9SStefano Zampini   if (scaling) {
95255d1c2e58SMatthew G. Knepley     /* Use naive scaling */
95269566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
95274db47ee9SStefano Zampini   }
9528a063dac3SMatthew G. Knepley   PetscFunctionReturn(0);
9529a063dac3SMatthew G. Knepley }
9530bceba477SMatthew G. Knepley 
9531d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9532d71ae5a4SJacob Faibussowitsch {
95336dbf9973SLawrence Mitchell   VecScatter ctx;
953490748bafSMatthew G. Knepley 
9535a063dac3SMatthew G. Knepley   PetscFunctionBegin;
95369566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
95379566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
95389566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
9539bceba477SMatthew G. Knepley   PetscFunctionReturn(0);
9540bceba477SMatthew G. Knepley }
9541bceba477SMatthew G. Knepley 
9542d71ae5a4SJacob 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[])
9543d71ae5a4SJacob Faibussowitsch {
954400635df3SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
954500635df3SMatthew G. Knepley   PetscInt       c;
954600635df3SMatthew G. Knepley   for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
95473e9753d6SMatthew G. Knepley }
95483e9753d6SMatthew G. Knepley 
9549d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9550d71ae5a4SJacob Faibussowitsch {
9551b4937a87SMatthew G. Knepley   DM           dmc;
9552b4937a87SMatthew G. Knepley   PetscDS      ds;
9553b4937a87SMatthew G. Knepley   Vec          ones, locmass;
9554b4937a87SMatthew G. Knepley   IS           cellIS;
9555b4937a87SMatthew G. Knepley   PetscFormKey key;
9556b4937a87SMatthew G. Knepley   PetscInt     depth;
9557b4937a87SMatthew G. Knepley 
9558b4937a87SMatthew G. Knepley   PetscFunctionBegin;
95599566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
95609566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
95619566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
95629566063dSJacob Faibussowitsch   PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
95639566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmc, mass));
95649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &ones));
95659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &locmass));
95669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmc, &depth));
95679566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
95689566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
95699566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
9570b4937a87SMatthew G. Knepley   key.label = NULL;
9571b4937a87SMatthew G. Knepley   key.value = 0;
9572b4937a87SMatthew G. Knepley   key.field = 0;
9573b4937a87SMatthew G. Knepley   key.part  = 0;
95749566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
95759566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
95769566063dSJacob Faibussowitsch   PetscCall(VecSet(*mass, 0.0));
95779566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
95789566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
95799566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &ones));
95809566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &locmass));
95819566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
9582b4937a87SMatthew G. Knepley   PetscFunctionReturn(0);
9583b4937a87SMatthew G. Knepley }
9584b4937a87SMatthew G. Knepley 
9585d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9586d71ae5a4SJacob Faibussowitsch {
9587bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
9588bd041c0cSMatthew G. Knepley   PetscInt     m, n;
9589bd041c0cSMatthew G. Knepley   void        *ctx;
9590bd041c0cSMatthew G. Knepley   DM           cdm;
9591bd041c0cSMatthew G. Knepley   PetscBool    regular;
9592bd041c0cSMatthew G. Knepley 
9593bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
95943e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
95953e9753d6SMatthew G. Knepley     DM            dmc;
95963e9753d6SMatthew G. Knepley     PetscDS       ds;
9597b4937a87SMatthew G. Knepley     PetscWeakForm wf;
95983e9753d6SMatthew G. Knepley     Vec           u;
95993e9753d6SMatthew G. Knepley     IS            cellIS;
960006ad1575SMatthew G. Knepley     PetscFormKey  key;
96013e9753d6SMatthew G. Knepley     PetscInt      depth;
96023e9753d6SMatthew G. Knepley 
96039566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
96049566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
96059566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
96069566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
96079566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
96089566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
96099566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
96108d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
96119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
96129566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
96139566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
96146528b96dSMatthew G. Knepley     key.label = NULL;
96156528b96dSMatthew G. Knepley     key.value = 0;
96166528b96dSMatthew G. Knepley     key.field = 0;
961706ad1575SMatthew G. Knepley     key.part  = 0;
96189566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
96199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
96208d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
96219566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
96223e9753d6SMatthew G. Knepley   } else {
96239566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
96249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
96259566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
96269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
9627bd041c0cSMatthew G. Knepley 
96289566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
96299566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
96309566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
96319566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
9632bd041c0cSMatthew G. Knepley 
96339566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
96349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
96359566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
96369566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
96373e9753d6SMatthew G. Knepley   }
96389566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
9639bd041c0cSMatthew G. Knepley   PetscFunctionReturn(0);
9640bd041c0cSMatthew G. Knepley }
9641bd041c0cSMatthew G. Knepley 
96420aef6b92SMatthew G. Knepley /*@
96430aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
96440aef6b92SMatthew G. Knepley 
96450aef6b92SMatthew G. Knepley   Input Parameter:
96460aef6b92SMatthew G. Knepley . dm - The DMPlex object
96470aef6b92SMatthew G. Knepley 
96480aef6b92SMatthew G. Knepley   Output Parameter:
96490aef6b92SMatthew G. Knepley . regular - The flag
96500aef6b92SMatthew G. Knepley 
96510aef6b92SMatthew G. Knepley   Level: intermediate
96520aef6b92SMatthew G. Knepley 
9653db781477SPatrick Sanan .seealso: `DMPlexSetRegularRefinement()`
96540aef6b92SMatthew G. Knepley @*/
9655d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9656d71ae5a4SJacob Faibussowitsch {
96570aef6b92SMatthew G. Knepley   PetscFunctionBegin;
96580aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9659dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(regular, 2);
96600aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
96610aef6b92SMatthew G. Knepley   PetscFunctionReturn(0);
96620aef6b92SMatthew G. Knepley }
96630aef6b92SMatthew G. Knepley 
96640aef6b92SMatthew G. Knepley /*@
96650aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
96660aef6b92SMatthew G. Knepley 
96670aef6b92SMatthew G. Knepley   Input Parameters:
96680aef6b92SMatthew G. Knepley + dm - The DMPlex object
96690aef6b92SMatthew G. Knepley - regular - The flag
96700aef6b92SMatthew G. Knepley 
96710aef6b92SMatthew G. Knepley   Level: intermediate
96720aef6b92SMatthew G. Knepley 
9673db781477SPatrick Sanan .seealso: `DMPlexGetRegularRefinement()`
96740aef6b92SMatthew G. Knepley @*/
9675d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9676d71ae5a4SJacob Faibussowitsch {
96770aef6b92SMatthew G. Knepley   PetscFunctionBegin;
96780aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
96790aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
96800aef6b92SMatthew G. Knepley   PetscFunctionReturn(0);
96810aef6b92SMatthew G. Knepley }
96820aef6b92SMatthew G. Knepley 
9683f7c74593SToby Isaac /* anchors */
9684a68b90caSToby Isaac /*@
9685f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9686ebdb1bfaSJed Brown   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints().
9687a68b90caSToby Isaac 
9688e228b242SToby Isaac   not collective
9689a68b90caSToby Isaac 
9690f899ff85SJose E. Roman   Input Parameter:
9691a68b90caSToby Isaac . dm - The DMPlex object
9692a68b90caSToby Isaac 
9693a68b90caSToby Isaac   Output Parameters:
9694a68b90caSToby Isaac + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9695a68b90caSToby Isaac - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9696a68b90caSToby Isaac 
9697a68b90caSToby Isaac   Level: intermediate
9698a68b90caSToby Isaac 
9699db781477SPatrick Sanan .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9700a68b90caSToby Isaac @*/
9701d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9702d71ae5a4SJacob Faibussowitsch {
9703a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
9704a68b90caSToby Isaac 
9705a68b90caSToby Isaac   PetscFunctionBegin;
9706a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
97079566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
9708a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
9709a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
9710a68b90caSToby Isaac   PetscFunctionReturn(0);
9711a68b90caSToby Isaac }
9712a68b90caSToby Isaac 
9713a68b90caSToby Isaac /*@
9714f7c74593SToby Isaac   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9715f7c74593SToby Isaac   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9716a68b90caSToby Isaac   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9717a68b90caSToby Isaac 
9718a17985deSToby Isaac   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9719ebdb1bfaSJed Brown   DMGetDefaultConstraints() and filling in the entries in the constraint matrix.
9720a68b90caSToby Isaac 
9721e228b242SToby Isaac   collective on dm
9722a68b90caSToby Isaac 
9723a68b90caSToby Isaac   Input Parameters:
9724a68b90caSToby Isaac + dm - The DMPlex object
9725e228b242SToby Isaac . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9726e228b242SToby Isaac - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9727a68b90caSToby Isaac 
9728a68b90caSToby Isaac   The reference counts of anchorSection and anchorIS are incremented.
9729a68b90caSToby Isaac 
9730a68b90caSToby Isaac   Level: intermediate
9731a68b90caSToby Isaac 
9732db781477SPatrick Sanan .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9733a68b90caSToby Isaac @*/
9734d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9735d71ae5a4SJacob Faibussowitsch {
9736a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
9737e228b242SToby Isaac   PetscMPIInt result;
9738a68b90caSToby Isaac 
9739a68b90caSToby Isaac   PetscFunctionBegin;
9740a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9741e228b242SToby Isaac   if (anchorSection) {
9742e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
97439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
97441dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
9745e228b242SToby Isaac   }
9746e228b242SToby Isaac   if (anchorIS) {
9747e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
97489566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
97491dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
9750e228b242SToby Isaac   }
9751a68b90caSToby Isaac 
97529566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
97539566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
9754a68b90caSToby Isaac   plex->anchorSection = anchorSection;
9755a68b90caSToby Isaac 
97569566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
97579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
9758a68b90caSToby Isaac   plex->anchorIS = anchorIS;
9759a68b90caSToby Isaac 
9760cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9761a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
9762a68b90caSToby Isaac     const PetscInt *anchors;
9763a68b90caSToby Isaac 
97649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
97659566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
97669566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
9767a68b90caSToby Isaac     for (a = 0; a < size; a++) {
9768a68b90caSToby Isaac       PetscInt p;
9769a68b90caSToby Isaac 
9770a68b90caSToby Isaac       p = anchors[a];
9771a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
9772a68b90caSToby Isaac         PetscInt dof;
9773a68b90caSToby Isaac 
97749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
9775a68b90caSToby Isaac         if (dof) {
97769566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
977763a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
9778a68b90caSToby Isaac         }
9779a68b90caSToby Isaac       }
9780a68b90caSToby Isaac     }
97819566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
9782a68b90caSToby Isaac   }
9783f7c74593SToby Isaac   /* reset the generic constraints */
97849566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
9785a68b90caSToby Isaac   PetscFunctionReturn(0);
9786a68b90caSToby Isaac }
9787a68b90caSToby Isaac 
9788d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9789d71ae5a4SJacob Faibussowitsch {
9790f7c74593SToby Isaac   PetscSection anchorSection;
97916995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9792a68b90caSToby Isaac 
9793a68b90caSToby Isaac   PetscFunctionBegin;
9794a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
97959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
97969566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
97979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
97986995de1eSToby Isaac   if (numFields) {
9799719ab38cSToby Isaac     PetscInt f;
98009566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
9801719ab38cSToby Isaac 
9802719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
9803719ab38cSToby Isaac       PetscInt numComp;
9804719ab38cSToby Isaac 
98059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
98069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
9807719ab38cSToby Isaac     }
98086995de1eSToby Isaac   }
98099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
98109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
98116995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
98126995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
98136995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
98149566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
9815a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
98169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
9817a68b90caSToby Isaac     if (dof) {
98189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
98199566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
9820a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
98219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
98229566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
9823a68b90caSToby Isaac       }
9824a68b90caSToby Isaac     }
9825a68b90caSToby Isaac   }
98269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
98279566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
9828a68b90caSToby Isaac   PetscFunctionReturn(0);
9829a68b90caSToby Isaac }
9830a68b90caSToby Isaac 
9831d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9832d71ae5a4SJacob Faibussowitsch {
9833f7c74593SToby Isaac   PetscSection    aSec;
9834ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
98350ac89760SToby Isaac   const PetscInt *anchors;
98360ac89760SToby Isaac   PetscInt        numFields, f;
983766ad2231SToby Isaac   IS              aIS;
9838e19f7ee6SMark Adams   MatType         mtype;
9839e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
98400ac89760SToby Isaac 
98410ac89760SToby Isaac   PetscFunctionBegin;
98420ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
98439566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
98449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
98459566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
98469566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
98479566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
98489566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
98499566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
98509566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
9851e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9852e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9853e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
98549566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
98559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
98569566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
98576995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
98589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
98599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
98609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
98610ac89760SToby Isaac   i[0] = 0;
98629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
98630ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
9864f19733c5SToby Isaac     PetscInt rDof, rOff, r;
9865f19733c5SToby Isaac 
98669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
9867f19733c5SToby Isaac     if (!rDof) continue;
98689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
98690ac89760SToby Isaac     if (numFields) {
98700ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
98710ac89760SToby Isaac         annz = 0;
9872f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
9873f19733c5SToby Isaac           a = anchors[rOff + r];
9874ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
98759566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
98760ac89760SToby Isaac           annz += aDof;
98770ac89760SToby Isaac         }
98789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
98799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
9880ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
98810ac89760SToby Isaac       }
98822f7452b8SBarry Smith     } else {
98830ac89760SToby Isaac       annz = 0;
98849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
98850ac89760SToby Isaac       for (q = 0; q < dof; q++) {
9886ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
9887ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
98889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
98890ac89760SToby Isaac         annz += aDof;
98900ac89760SToby Isaac       }
98919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
98929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
9893ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
98940ac89760SToby Isaac     }
98950ac89760SToby Isaac   }
98960ac89760SToby Isaac   nnz = i[m];
98979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
98980ac89760SToby Isaac   offset = 0;
98990ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
99000ac89760SToby Isaac     if (numFields) {
99010ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
99029566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
99030ac89760SToby Isaac         for (q = 0; q < dof; q++) {
99040ac89760SToby Isaac           PetscInt rDof, rOff, r;
99059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
99069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
99070ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
99080ac89760SToby Isaac             PetscInt s;
99090ac89760SToby Isaac 
99100ac89760SToby Isaac             a = anchors[rOff + r];
9911ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
99129566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
99139566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
9914ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
99150ac89760SToby Isaac           }
99160ac89760SToby Isaac         }
99170ac89760SToby Isaac       }
99182f7452b8SBarry Smith     } else {
99199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
99200ac89760SToby Isaac       for (q = 0; q < dof; q++) {
99210ac89760SToby Isaac         PetscInt rDof, rOff, r;
99229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
99239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
99240ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
99250ac89760SToby Isaac           PetscInt s;
99260ac89760SToby Isaac 
99270ac89760SToby Isaac           a = anchors[rOff + r];
9928ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
99299566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
99309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
9931ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
99320ac89760SToby Isaac         }
99330ac89760SToby Isaac       }
99340ac89760SToby Isaac     }
99350ac89760SToby Isaac   }
99369566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
99379566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
99389566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
99399566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
99400ac89760SToby Isaac   PetscFunctionReturn(0);
99410ac89760SToby Isaac }
99420ac89760SToby Isaac 
9943d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9944d71ae5a4SJacob Faibussowitsch {
9945f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
9946f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
994766ad2231SToby Isaac   Mat          cMat;
994866ad2231SToby Isaac 
994966ad2231SToby Isaac   PetscFunctionBegin;
995066ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
99519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
995266ad2231SToby Isaac   if (anchorSection) {
995344a7f3ddSMatthew G. Knepley     PetscInt Nf;
9954e228b242SToby Isaac 
99559566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
99569566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
99579566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
99589566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
99599566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
99609566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
99619566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
99629566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
996366ad2231SToby Isaac   }
996466ad2231SToby Isaac   PetscFunctionReturn(0);
996566ad2231SToby Isaac }
9966a93c429eSMatthew G. Knepley 
9967d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9968d71ae5a4SJacob Faibussowitsch {
9969a93c429eSMatthew G. Knepley   IS           subis;
9970a93c429eSMatthew G. Knepley   PetscSection section, subsection;
9971a93c429eSMatthew G. Knepley 
9972a93c429eSMatthew G. Knepley   PetscFunctionBegin;
99739566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
997428b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
997528b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9976a93c429eSMatthew G. Knepley   /* Create subdomain */
99779566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dm, label, value, subdm));
9978a93c429eSMatthew G. Knepley   /* Create submodel */
99799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
99809566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
99819566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
99829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
99839566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
9984a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
9985a93c429eSMatthew G. Knepley   if (is) {
9986a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
9987a93c429eSMatthew G. Knepley     IS              spIS;
9988a93c429eSMatthew G. Knepley     const PetscInt *spmap;
9989a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
9990a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9991a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9992a93c429eSMatthew G. Knepley 
99939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
99949566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
99959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
99969566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
99979566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
99989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
9999a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10000a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10001a93c429eSMatthew G. Knepley 
100029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10003a93c429eSMatthew G. Knepley       if (gdof > 0) {
10004a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10005a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10006a93c429eSMatthew G. Knepley 
100079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
100089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10009a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10010a93c429eSMatthew G. Knepley         }
10011a93c429eSMatthew G. Knepley         subSize += pSubSize;
10012a93c429eSMatthew G. Knepley         if (pSubSize) {
10013a93c429eSMatthew G. Knepley           if (bs < 0) {
10014a93c429eSMatthew G. Knepley             bs = pSubSize;
10015a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10016a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10017a93c429eSMatthew G. Knepley             bs = 1;
10018a93c429eSMatthew G. Knepley           }
10019a93c429eSMatthew G. Knepley         }
10020a93c429eSMatthew G. Knepley       }
10021a93c429eSMatthew G. Knepley     }
10022a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
100239371c9d4SSatish Balay     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
100249371c9d4SSatish Balay     bsLocal[1] = bs;
100259566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
100269371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
100279371c9d4SSatish Balay       bs = 1;
100289371c9d4SSatish Balay     } else {
100299371c9d4SSatish Balay       bs = bsMinMax[0];
100309371c9d4SSatish Balay     }
100319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10032a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10033a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10034a93c429eSMatthew G. Knepley 
100359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10036a93c429eSMatthew G. Knepley       if (gdof > 0) {
10037a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10038a93c429eSMatthew G. Knepley 
100399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10040a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10041a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10042a93c429eSMatthew G. Knepley 
10043a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10044a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
100459566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
100469566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10047a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10048a93c429eSMatthew G. Knepley           }
100499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
100509566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10051ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10052a93c429eSMatthew G. Knepley         }
10053a93c429eSMatthew G. Knepley       }
10054a93c429eSMatthew G. Knepley     }
100559566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
100569566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10057a93c429eSMatthew G. Knepley     if (bs > 1) {
10058a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10059a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10060a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10061a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
100629371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
100639371c9d4SSatish Balay             set = 0;
100649371c9d4SSatish Balay             break;
100659371c9d4SSatish Balay           }
10066a93c429eSMatthew G. Knepley         }
10067a93c429eSMatthew G. Knepley       }
100689566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10069a93c429eSMatthew G. Knepley     }
10070a93c429eSMatthew G. Knepley     /* Attach nullspace */
10071a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
10072a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10073a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
10074a93c429eSMatthew G. Knepley     }
10075a93c429eSMatthew G. Knepley     if (f < Nf) {
10076a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
100779566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
100786823f3c5SBlaise Bourdin 
100799566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
100809566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
10081a93c429eSMatthew G. Knepley     }
10082a93c429eSMatthew G. Knepley   }
10083a93c429eSMatthew G. Knepley   PetscFunctionReturn(0);
10084a93c429eSMatthew G. Knepley }
10085c0f0dcc3SMatthew G. Knepley 
10086c0f0dcc3SMatthew G. Knepley /*@
10087c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10088c0f0dcc3SMatthew G. Knepley 
10089c0f0dcc3SMatthew G. Knepley   Input Parameter:
10090c0f0dcc3SMatthew G. Knepley - dm - The DM
10091c0f0dcc3SMatthew G. Knepley 
10092c0f0dcc3SMatthew G. Knepley   Level: developer
10093c0f0dcc3SMatthew G. Knepley 
10094c0f0dcc3SMatthew G. Knepley   Options Database Keys:
10095c0f0dcc3SMatthew G. Knepley . -dm_plex_monitor_throughput - Activate the monitor
10096c0f0dcc3SMatthew G. Knepley 
10097db781477SPatrick Sanan .seealso: `DMSetFromOptions()`, `DMPlexCreate()`
10098c0f0dcc3SMatthew G. Knepley @*/
10099d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
10100d71ae5a4SJacob Faibussowitsch {
10101e5ed2c37SJose E. Roman #if defined(PETSC_USE_LOG)
10102c0f0dcc3SMatthew G. Knepley   PetscStageLog      stageLog;
10103c0f0dcc3SMatthew G. Knepley   PetscLogEvent      event;
10104c0f0dcc3SMatthew G. Knepley   PetscLogStage      stage;
10105c0f0dcc3SMatthew G. Knepley   PetscEventPerfInfo eventInfo;
10106c0f0dcc3SMatthew G. Knepley   PetscReal          cellRate, flopRate;
10107c0f0dcc3SMatthew G. Knepley   PetscInt           cStart, cEnd, Nf, N;
10108c0f0dcc3SMatthew G. Knepley   const char        *name;
10109e5ed2c37SJose E. Roman #endif
10110c0f0dcc3SMatthew G. Knepley 
10111c0f0dcc3SMatthew G. Knepley   PetscFunctionBegin;
10112c0f0dcc3SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10113c0f0dcc3SMatthew G. Knepley #if defined(PETSC_USE_LOG)
101149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
101159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
101169566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
101179566063dSJacob Faibussowitsch   PetscCall(PetscLogGetStageLog(&stageLog));
101189566063dSJacob Faibussowitsch   PetscCall(PetscStageLogGetCurrent(stageLog, &stage));
101199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
101209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo));
10121c0f0dcc3SMatthew G. Knepley   N        = (cEnd - cStart) * Nf * eventInfo.count;
10122c0f0dcc3SMatthew G. Knepley   flopRate = eventInfo.flops / eventInfo.time;
10123c0f0dcc3SMatthew G. Knepley   cellRate = N / eventInfo.time;
1012463a3b9bcSJacob 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)));
10125c0f0dcc3SMatthew G. Knepley #else
10126c0f0dcc3SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
10127c0f0dcc3SMatthew G. Knepley #endif
10128c0f0dcc3SMatthew G. Knepley   PetscFunctionReturn(0);
10129c0f0dcc3SMatthew G. Knepley }
10130