xref: /petsc/src/dm/impls/plex/plex.c (revision 4fb89dddf56594b92bdd2ca7e24874fafe134f45)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3e5c6e791SKarl Rupp #include <petsc/private/vecimpl.h>
48135c375SStefano Zampini #include <petsc/private/glvisvecimpl.h>
50c312b8eSJed Brown #include <petscsf.h>
6e228b242SToby Isaac #include <petscds.h>
7e412dcbdSMatthew G. Knepley #include <petscdraw.h>
8f19dbd58SToby Isaac #include <petscdmfield.h>
9012bc364SMatthew G. Knepley #include <petscdmplextransform.h>
10552f7358SJed Brown 
11552f7358SJed Brown /* Logging support */
1202f7d72cSksagiyam 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;
13552f7358SJed Brown 
145a576424SJed Brown PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15552f7358SJed Brown 
16e5337592SStefano Zampini /*@
179318fe57SMatthew G. Knepley   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
189318fe57SMatthew G. Knepley 
199318fe57SMatthew G. Knepley   Input Parameter:
209318fe57SMatthew G. Knepley . dm      - The DMPlex object
219318fe57SMatthew G. Knepley 
229318fe57SMatthew G. Knepley   Output Parameter:
239318fe57SMatthew G. Knepley . simplex - Flag checking for a simplex
249318fe57SMatthew G. Knepley 
259318fe57SMatthew 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.
269318fe57SMatthew G. Knepley   If the mesh has no cells, this returns PETSC_FALSE.
279318fe57SMatthew G. Knepley 
289318fe57SMatthew G. Knepley   Level: intermediate
299318fe57SMatthew G. Knepley 
30db781477SPatrick Sanan .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
319318fe57SMatthew G. Knepley @*/
329318fe57SMatthew G. Knepley PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
339318fe57SMatthew G. Knepley {
349318fe57SMatthew G. Knepley   DMPolytopeType ct;
359318fe57SMatthew G. Knepley   PetscInt       cStart, cEnd;
369318fe57SMatthew G. Knepley 
379318fe57SMatthew G. Knepley   PetscFunctionBegin;
389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
399318fe57SMatthew G. Knepley   if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);}
409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
419318fe57SMatthew G. Knepley   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
429318fe57SMatthew G. Knepley   PetscFunctionReturn(0);
439318fe57SMatthew G. Knepley }
449318fe57SMatthew G. Knepley 
459318fe57SMatthew G. Knepley /*@
46412e9a14SMatthew G. Knepley   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
47e5337592SStefano Zampini 
48d8d19677SJose E. Roman   Input Parameters:
49412e9a14SMatthew G. Knepley + dm     - The DMPlex object
50412e9a14SMatthew G. Knepley - height - The cell height in the Plex, 0 is the default
51e5337592SStefano Zampini 
52e5337592SStefano Zampini   Output Parameters:
53412e9a14SMatthew G. Knepley + cStart - The first "normal" cell
54412e9a14SMatthew G. Knepley - cEnd   - The upper bound on "normal"" cells
55e5337592SStefano Zampini 
56412e9a14SMatthew 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.
57e5337592SStefano Zampini 
58412e9a14SMatthew G. Knepley   Level: developer
59e5337592SStefano Zampini 
60db781477SPatrick Sanan .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()`
61e5337592SStefano Zampini @*/
62412e9a14SMatthew G. Knepley PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
63e5337592SStefano Zampini {
64412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
65412e9a14SMatthew G. Knepley   PetscInt       cS, cE, c;
66e5337592SStefano Zampini 
67e5337592SStefano Zampini   PetscFunctionBegin;
689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE));
69412e9a14SMatthew G. Knepley   for (c = cS; c < cE; ++c) {
70412e9a14SMatthew G. Knepley     DMPolytopeType cct;
71412e9a14SMatthew G. Knepley 
729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &cct));
73412e9a14SMatthew G. Knepley     if ((PetscInt) cct < 0) break;
74412e9a14SMatthew G. Knepley     switch (cct) {
75ba2698f1SMatthew G. Knepley       case DM_POLYTOPE_POINT:
76ba2698f1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
77ba2698f1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
78ba2698f1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
79ba2698f1SMatthew G. Knepley       case DM_POLYTOPE_TETRAHEDRON:
80ba2698f1SMatthew G. Knepley       case DM_POLYTOPE_HEXAHEDRON:
81412e9a14SMatthew G. Knepley         ct = cct;
82e5337592SStefano Zampini         break;
83412e9a14SMatthew G. Knepley       default: break;
84e5337592SStefano Zampini     }
85412e9a14SMatthew G. Knepley     if (ct != DM_POLYTOPE_UNKNOWN) break;
86e5337592SStefano Zampini   }
87412e9a14SMatthew G. Knepley   if (ct != DM_POLYTOPE_UNKNOWN) {
88412e9a14SMatthew G. Knepley     DMLabel ctLabel;
89412e9a14SMatthew G. Knepley 
909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
919566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE));
92e5337592SStefano Zampini   }
93412e9a14SMatthew G. Knepley   if (cStart) *cStart = cS;
94412e9a14SMatthew G. Knepley   if (cEnd)   *cEnd   = cE;
95e5337592SStefano Zampini   PetscFunctionReturn(0);
96e5337592SStefano Zampini }
97e5337592SStefano Zampini 
987afe7537SMatthew G. Knepley PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
997e42fee7SMatthew G. Knepley {
100412e9a14SMatthew G. Knepley   PetscInt       cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
101a99a26bcSAdrian Croucher   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
1027e42fee7SMatthew G. Knepley 
1037e42fee7SMatthew G. Knepley   PetscFunctionBegin;
104e630c359SToby Isaac   *ft  = PETSC_VTK_INVALID;
1059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1097e42fee7SMatthew G. Knepley   if (field >= 0) {
1109566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
1119566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
1127e42fee7SMatthew G. Knepley   } else {
1139566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
1149566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
1157e42fee7SMatthew G. Knepley   }
1169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
117a99a26bcSAdrian Croucher   if (globalvcdof[0]) {
1187e42fee7SMatthew G. Knepley     *sStart = vStart;
1197e42fee7SMatthew G. Knepley     *sEnd   = vEnd;
120f094498dSMatthew G. Knepley     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
1217e42fee7SMatthew G. Knepley     else                        *ft = PETSC_VTK_POINT_FIELD;
122a99a26bcSAdrian Croucher   } else if (globalvcdof[1]) {
1237e42fee7SMatthew G. Knepley     *sStart = cStart;
1247e42fee7SMatthew G. Knepley     *sEnd   = cEnd;
125f094498dSMatthew G. Knepley     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
1267e42fee7SMatthew G. Knepley     else                        *ft = PETSC_VTK_CELL_FIELD;
127e630c359SToby Isaac   } else {
128e630c359SToby Isaac     if (field >= 0) {
129e630c359SToby Isaac       const char *fieldname;
130e630c359SToby Isaac 
1319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
13263a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
133e630c359SToby Isaac     } else {
13463a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n"));
135e630c359SToby Isaac     }
136e630c359SToby Isaac   }
1377e42fee7SMatthew G. Knepley   PetscFunctionReturn(0);
1387e42fee7SMatthew G. Knepley }
1397e42fee7SMatthew G. Knepley 
1406913077dSMatthew G. Knepley /*@
1416913077dSMatthew G. Knepley   DMPlexVecView1D - Plot many 1D solutions on the same line graph
1426913077dSMatthew G. Knepley 
1436913077dSMatthew G. Knepley   Collective on dm
1446913077dSMatthew G. Knepley 
1456913077dSMatthew G. Knepley   Input Parameters:
1466913077dSMatthew G. Knepley + dm - The DMPlex
1476913077dSMatthew G. Knepley . n  - The number of vectors
1486913077dSMatthew G. Knepley . u  - The array of local vectors
1496913077dSMatthew G. Knepley - viewer - The Draw viewer
1506913077dSMatthew G. Knepley 
1516913077dSMatthew G. Knepley   Level: advanced
1526913077dSMatthew G. Knepley 
153db781477SPatrick Sanan .seealso: `VecViewFromOptions()`, `VecView()`
1546913077dSMatthew G. Knepley @*/
1556913077dSMatthew G. Knepley PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
1566913077dSMatthew G. Knepley {
1576913077dSMatthew G. Knepley   PetscDS            ds;
1586913077dSMatthew G. Knepley   PetscDraw          draw = NULL;
1596913077dSMatthew G. Knepley   PetscDrawLG        lg;
1606913077dSMatthew G. Knepley   Vec                coordinates;
1616913077dSMatthew G. Knepley   const PetscScalar *coords, **sol;
1626913077dSMatthew G. Knepley   PetscReal         *vals;
1636913077dSMatthew G. Knepley   PetscInt          *Nc;
1646913077dSMatthew G. Knepley   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
1656913077dSMatthew G. Knepley   char             **names;
1666913077dSMatthew G. Knepley 
1676913077dSMatthew G. Knepley   PetscFunctionBegin;
1689566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
1699566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
1709566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
1719566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponents(ds, &Nc));
1726913077dSMatthew G. Knepley 
1739566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1746913077dSMatthew G. Knepley   if (!draw) PetscFunctionReturn(0);
1759566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg));
1766913077dSMatthew G. Knepley 
1779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals));
1786913077dSMatthew G. Knepley   for (i = 0, l = 0; i < n; ++i) {
1796913077dSMatthew G. Knepley     const char *vname;
1806913077dSMatthew G. Knepley 
1819566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) u[i], &vname));
1826913077dSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
1836913077dSMatthew G. Knepley       PetscObject disc;
1846913077dSMatthew G. Knepley       const char *fname;
1856913077dSMatthew G. Knepley       char        tmpname[PETSC_MAX_PATH_LEN];
1866913077dSMatthew G. Knepley 
1879566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
1886913077dSMatthew G. Knepley       /* TODO Create names for components */
1896913077dSMatthew G. Knepley       for (c = 0; c < Nc[f]; ++c, ++l) {
1909566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(disc, &fname));
1919566063dSJacob Faibussowitsch         PetscCall(PetscStrcpy(tmpname, vname));
1929566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN));
1939566063dSJacob Faibussowitsch         PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN));
1949566063dSJacob Faibussowitsch         PetscCall(PetscStrallocpy(tmpname, &names[l]));
1956913077dSMatthew G. Knepley       }
1966913077dSMatthew G. Knepley     }
1976913077dSMatthew G. Knepley   }
1989566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names));
1996913077dSMatthew G. Knepley   /* Just add P_1 support for now */
2009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2019566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2029566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
2039566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
2046913077dSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
2056913077dSMatthew G. Knepley     PetscScalar *x, *svals;
2066913077dSMatthew G. Knepley 
2079566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
2086913077dSMatthew G. Knepley     for (i = 0; i < n; ++i) {
2099566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
2106913077dSMatthew G. Knepley       for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]);
2116913077dSMatthew G. Knepley     }
2129566063dSJacob Faibussowitsch     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
2136913077dSMatthew G. Knepley   }
2149566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
2159566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
2169566063dSJacob Faibussowitsch   for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l]));
2179566063dSJacob Faibussowitsch   PetscCall(PetscFree3(sol, names, vals));
2186913077dSMatthew G. Knepley 
2199566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDraw(lg));
2209566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDestroy(&lg));
2216913077dSMatthew G. Knepley   PetscFunctionReturn(0);
2226913077dSMatthew G. Knepley }
2236913077dSMatthew G. Knepley 
2246913077dSMatthew G. Knepley static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
2256913077dSMatthew G. Knepley {
2266913077dSMatthew G. Knepley   DM             dm;
2276913077dSMatthew G. Knepley 
2286913077dSMatthew G. Knepley   PetscFunctionBegin;
2299566063dSJacob Faibussowitsch   PetscCall(VecGetDM(u, &dm));
2309566063dSJacob Faibussowitsch   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
2316913077dSMatthew G. Knepley   PetscFunctionReturn(0);
2326913077dSMatthew G. Knepley }
2336913077dSMatthew G. Knepley 
2346913077dSMatthew G. Knepley static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
235e412dcbdSMatthew G. Knepley {
236e412dcbdSMatthew G. Knepley   DM                 dm;
237d1df6f1dSMatthew G. Knepley   PetscSection       s;
238e412dcbdSMatthew G. Knepley   PetscDraw          draw, popup;
239e412dcbdSMatthew G. Knepley   DM                 cdm;
240e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
241e412dcbdSMatthew G. Knepley   Vec                coordinates;
242e412dcbdSMatthew G. Knepley   const PetscScalar *coords, *array;
243e412dcbdSMatthew G. Knepley   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
244339e3443SMatthew G. Knepley   PetscReal          vbound[2], time;
2456913077dSMatthew G. Knepley   PetscBool          flg;
246d1df6f1dSMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
247e412dcbdSMatthew G. Knepley   const char        *name;
248339e3443SMatthew G. Knepley   char               title[PETSC_MAX_PATH_LEN];
249e412dcbdSMatthew G. Knepley 
250e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
2519566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2529566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
2539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
2549566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
2559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
2569566063dSJacob Faibussowitsch   PetscCall(DMGetCoarsenLevel(dm, &level));
2579566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
2589566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
2599566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
262e412dcbdSMatthew G. Knepley 
2639566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject) v, &name));
2649566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
265e412dcbdSMatthew G. Knepley 
2669566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
2679566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
268e412dcbdSMatthew G. Knepley   for (c = 0; c < N; c += dim) {
2690c81f2a8SMatthew G. Knepley     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
2700c81f2a8SMatthew G. Knepley     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
271e412dcbdSMatthew G. Knepley   }
2729566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
2739566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
274e412dcbdSMatthew G. Knepley 
275d1df6f1dSMatthew G. Knepley   /* Could implement something like DMDASelectFields() */
276d1df6f1dSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
277d1df6f1dSMatthew G. Knepley     DM   fdm = dm;
278d1df6f1dSMatthew G. Knepley     Vec  fv  = v;
279d1df6f1dSMatthew G. Knepley     IS   fis;
280d1df6f1dSMatthew G. Knepley     char prefix[PETSC_MAX_PATH_LEN];
281d1df6f1dSMatthew G. Knepley     const char *fname;
282d1df6f1dSMatthew G. Knepley 
2839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(s, f, &fname));
285d1df6f1dSMatthew G. Knepley 
2869566063dSJacob Faibussowitsch     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix)));
287d1df6f1dSMatthew G. Knepley     else               {prefix[0] = '\0';}
288d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
2899566063dSJacob Faibussowitsch       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
2909566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(v, fis, &fv));
2919566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix)));
2929566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix)));
293d1df6f1dSMatthew G. Knepley     }
294d1df6f1dSMatthew G. Knepley     for (comp = 0; comp < Nc; ++comp, ++w) {
295d1df6f1dSMatthew G. Knepley       PetscInt nmax = 2;
296d1df6f1dSMatthew G. Knepley 
2979566063dSJacob Faibussowitsch       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
29863a3b9bcSJacob Faibussowitsch       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
29963a3b9bcSJacob Faibussowitsch       else        PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
3009566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetTitle(draw, title));
301d1df6f1dSMatthew G. Knepley 
302d1df6f1dSMatthew G. Knepley       /* TODO Get max and min only for this component */
3039566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
304339e3443SMatthew G. Knepley       if (!flg) {
3059566063dSJacob Faibussowitsch         PetscCall(VecMin(fv, NULL, &vbound[0]));
3069566063dSJacob Faibussowitsch         PetscCall(VecMax(fv, NULL, &vbound[1]));
307d1df6f1dSMatthew G. Knepley         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
308339e3443SMatthew G. Knepley       }
3099566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetPopup(draw, &popup));
3109566063dSJacob Faibussowitsch       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
3119566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]));
312e412dcbdSMatthew G. Knepley 
3139566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(fv, &array));
314e412dcbdSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
31599a2f7bcSMatthew G. Knepley         PetscScalar *coords = NULL, *a = NULL;
316e56f9228SJed Brown         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
317e412dcbdSMatthew G. Knepley 
3189566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
319339e3443SMatthew G. Knepley         if (a) {
320d1df6f1dSMatthew G. Knepley           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
321339e3443SMatthew G. Knepley           color[1] = color[2] = color[3] = color[0];
322339e3443SMatthew G. Knepley         } else {
323339e3443SMatthew G. Knepley           PetscScalar *vals = NULL;
324339e3443SMatthew G. Knepley           PetscInt     numVals, va;
325339e3443SMatthew G. Knepley 
3269566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
32763a3b9bcSJacob 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);
328d1df6f1dSMatthew G. Knepley           switch (numVals/Nc) {
329d1df6f1dSMatthew G. Knepley           case 3: /* P1 Triangle */
330d1df6f1dSMatthew G. Knepley           case 4: /* P1 Quadrangle */
331d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
332339e3443SMatthew G. Knepley             break;
333d1df6f1dSMatthew G. Knepley           case 6: /* P2 Triangle */
334d1df6f1dSMatthew G. Knepley           case 8: /* P2 Quadrangle */
335d1df6f1dSMatthew 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]);
336d1df6f1dSMatthew G. Knepley             break;
33763a3b9bcSJacob Faibussowitsch           default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc);
338339e3443SMatthew G. Knepley           }
3399566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
340339e3443SMatthew G. Knepley         }
3419566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
342e412dcbdSMatthew G. Knepley         switch (numCoords) {
343e412dcbdSMatthew G. Knepley         case 6:
3449edc3542SMatthew Knepley         case 12: /* Localized triangle */
3459566063dSJacob 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]));
346e412dcbdSMatthew G. Knepley           break;
347e412dcbdSMatthew G. Knepley         case 8:
3489edc3542SMatthew Knepley         case 16: /* Localized quadrilateral */
3499566063dSJacob 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]));
3509566063dSJacob 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]));
351e412dcbdSMatthew G. Knepley           break;
35263a3b9bcSJacob Faibussowitsch         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
353e412dcbdSMatthew G. Knepley         }
3549566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
355e412dcbdSMatthew G. Knepley       }
3569566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(fv, &array));
3579566063dSJacob Faibussowitsch       PetscCall(PetscDrawFlush(draw));
3589566063dSJacob Faibussowitsch       PetscCall(PetscDrawPause(draw));
3599566063dSJacob Faibussowitsch       PetscCall(PetscDrawSave(draw));
360d1df6f1dSMatthew G. Knepley     }
361d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
3629566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(v, fis, &fv));
3639566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&fis));
3649566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&fdm));
365d1df6f1dSMatthew G. Knepley     }
366d1df6f1dSMatthew G. Knepley   }
367e412dcbdSMatthew G. Knepley   PetscFunctionReturn(0);
368e412dcbdSMatthew G. Knepley }
369e412dcbdSMatthew G. Knepley 
3706913077dSMatthew G. Knepley static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
3716913077dSMatthew G. Knepley {
3726913077dSMatthew G. Knepley   DM        dm;
3736913077dSMatthew G. Knepley   PetscDraw draw;
3746913077dSMatthew G. Knepley   PetscInt  dim;
3756913077dSMatthew G. Knepley   PetscBool isnull;
3766913077dSMatthew G. Knepley 
3776913077dSMatthew G. Knepley   PetscFunctionBegin;
3789566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3799566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
3806913077dSMatthew G. Knepley   if (isnull) PetscFunctionReturn(0);
3816913077dSMatthew G. Knepley 
3829566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
3839566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
3846913077dSMatthew G. Knepley   switch (dim) {
3859566063dSJacob Faibussowitsch   case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break;
3869566063dSJacob Faibussowitsch   case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break;
3875f80ce2aSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
3886913077dSMatthew G. Knepley   }
3896913077dSMatthew G. Knepley   PetscFunctionReturn(0);
3906913077dSMatthew G. Knepley }
3916913077dSMatthew G. Knepley 
392684b87d9SLisandro Dalcin static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
393684b87d9SLisandro Dalcin {
394684b87d9SLisandro Dalcin   DM                      dm;
395684b87d9SLisandro Dalcin   Vec                     locv;
396684b87d9SLisandro Dalcin   const char              *name;
397684b87d9SLisandro Dalcin   PetscSection            section;
398684b87d9SLisandro Dalcin   PetscInt                pStart, pEnd;
399e630c359SToby Isaac   PetscInt                numFields;
400684b87d9SLisandro Dalcin   PetscViewerVTKFieldType ft;
401684b87d9SLisandro Dalcin 
402684b87d9SLisandro Dalcin   PetscFunctionBegin;
4039566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
4049566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
4059566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject) v, &name));
4069566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) locv, name));
4079566063dSJacob Faibussowitsch   PetscCall(VecCopy(v, locv));
4089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
4099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
410e630c359SToby Isaac   if (!numFields) {
4119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
4129566063dSJacob Faibussowitsch     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv));
413e630c359SToby Isaac   } else {
414e630c359SToby Isaac     PetscInt f;
415e630c359SToby Isaac 
416e630c359SToby Isaac     for (f = 0; f < numFields; f++) {
4179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
418e630c359SToby Isaac       if (ft == PETSC_VTK_INVALID) continue;
4199566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)locv));
4209566063dSJacob Faibussowitsch       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv));
421e630c359SToby Isaac     }
4229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locv));
423e630c359SToby Isaac   }
424684b87d9SLisandro Dalcin   PetscFunctionReturn(0);
425684b87d9SLisandro Dalcin }
426684b87d9SLisandro Dalcin 
427552f7358SJed Brown PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
428552f7358SJed Brown {
429552f7358SJed Brown   DM             dm;
430684b87d9SLisandro Dalcin   PetscBool      isvtk, ishdf5, isdraw, isglvis;
431552f7358SJed Brown 
432552f7358SJed Brown   PetscFunctionBegin;
4339566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
43428b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
4359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk));
4369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5));
4379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw));
4389566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis));
439684b87d9SLisandro Dalcin   if (isvtk || ishdf5 || isdraw || isglvis) {
440684b87d9SLisandro Dalcin     PetscInt    i,numFields;
441684b87d9SLisandro Dalcin     PetscObject fe;
442ef31f671SMatthew G. Knepley     PetscBool   fem = PETSC_FALSE;
443684b87d9SLisandro Dalcin     Vec         locv = v;
444684b87d9SLisandro Dalcin     const char  *name;
445684b87d9SLisandro Dalcin     PetscInt    step;
446684b87d9SLisandro Dalcin     PetscReal   time;
447ef31f671SMatthew G. Knepley 
4489566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &numFields));
449684b87d9SLisandro Dalcin     for (i=0; i<numFields; i++) {
4509566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, i, NULL, &fe));
451684b87d9SLisandro Dalcin       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
452ef31f671SMatthew G. Knepley     }
453684b87d9SLisandro Dalcin     if (fem) {
454798534f6SMatthew G. Knepley       PetscObject isZero;
455798534f6SMatthew G. Knepley 
4569566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &locv));
4579566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject) v, &name));
4589566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject) locv, name));
4599566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero));
4609566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero));
4619566063dSJacob Faibussowitsch       PetscCall(VecCopy(v, locv));
4629566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
4639566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
464ef31f671SMatthew G. Knepley     }
465552f7358SJed Brown     if (isvtk) {
4669566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
467b136c2c9SMatthew G. Knepley     } else if (ishdf5) {
468b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
4699566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
470b136c2c9SMatthew G. Knepley #else
471b136c2c9SMatthew G. Knepley       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
472b136c2c9SMatthew G. Knepley #endif
473f13a32a3SMatthew G. Knepley     } else if (isdraw) {
4749566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
475684b87d9SLisandro Dalcin     } else if (isglvis) {
4769566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
4779566063dSJacob Faibussowitsch       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
4789566063dSJacob Faibussowitsch       PetscCall(VecView_GLVis(locv, viewer));
479684b87d9SLisandro Dalcin     }
480798534f6SMatthew G. Knepley     if (fem) {
4819566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL));
4829566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &locv));
483798534f6SMatthew G. Knepley     }
484552f7358SJed Brown   } else {
485684b87d9SLisandro Dalcin     PetscBool isseq;
486684b87d9SLisandro Dalcin 
4879566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq));
4889566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
4899566063dSJacob Faibussowitsch     else       PetscCall(VecView_MPI(v, viewer));
490552f7358SJed Brown   }
491552f7358SJed Brown   PetscFunctionReturn(0);
492552f7358SJed Brown }
493552f7358SJed Brown 
494552f7358SJed Brown PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
495552f7358SJed Brown {
496552f7358SJed Brown   DM        dm;
4976823f3c5SBlaise Bourdin   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii;
498552f7358SJed Brown 
499552f7358SJed Brown   PetscFunctionBegin;
5009566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
50128b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5029566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk));
5039566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
5049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw));
5059566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis));
5069566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii));
507684b87d9SLisandro Dalcin   if (isvtk || isdraw || isglvis) {
508552f7358SJed Brown     Vec         locv;
509798534f6SMatthew G. Knepley     PetscObject isZero;
510552f7358SJed Brown     const char *name;
511552f7358SJed Brown 
5129566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &locv));
5139566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) v, &name));
5149566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject) locv, name));
5159566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
5169566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
5179566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero));
5189566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero));
5199566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_Local(locv, viewer));
5209566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL));
5219566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &locv));
522b136c2c9SMatthew G. Knepley   } else if (ishdf5) {
523b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
5249566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
525b136c2c9SMatthew G. Knepley #else
526b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
527b136c2c9SMatthew G. Knepley #endif
5286823f3c5SBlaise Bourdin   } else if (isexodusii) {
5296823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
5309566063dSJacob Faibussowitsch     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
5316823f3c5SBlaise Bourdin #else
5326823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
5336823f3c5SBlaise Bourdin #endif
534552f7358SJed Brown   } else {
535684b87d9SLisandro Dalcin     PetscBool isseq;
536684b87d9SLisandro Dalcin 
5379566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq));
5389566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
5399566063dSJacob Faibussowitsch     else       PetscCall(VecView_MPI(v, viewer));
540552f7358SJed Brown   }
541552f7358SJed Brown   PetscFunctionReturn(0);
542552f7358SJed Brown }
543552f7358SJed Brown 
544d930f514SMatthew G. Knepley PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
545d930f514SMatthew G. Knepley {
546d930f514SMatthew G. Knepley   DM                dm;
547d930f514SMatthew G. Knepley   MPI_Comm          comm;
548d930f514SMatthew G. Knepley   PetscViewerFormat format;
549d930f514SMatthew G. Knepley   Vec               v;
550d930f514SMatthew G. Knepley   PetscBool         isvtk, ishdf5;
551d930f514SMatthew G. Knepley 
552d930f514SMatthew G. Knepley   PetscFunctionBegin;
5539566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
5549566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm));
55528b400f6SJacob Faibussowitsch   PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5569566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
5579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
5589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk));
559d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
560a8ad634aSStefano Zampini     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
561a8ad634aSStefano Zampini     /* this need a better fix */
562a8ad634aSStefano Zampini     if (dm->useNatural) {
563a8ad634aSStefano Zampini       if (dm->sfNatural) {
564d930f514SMatthew G. Knepley         const char *vecname;
565d930f514SMatthew G. Knepley         PetscInt    n, nroots;
566d930f514SMatthew G. Knepley 
5679566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(originalv, &n));
5689566063dSJacob Faibussowitsch         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
569d930f514SMatthew G. Knepley         if (n == nroots) {
5709566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalVector(dm, &v));
5719566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
5729566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
5739566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname));
5749566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject) v, vecname));
575d930f514SMatthew G. Knepley         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
576d930f514SMatthew G. Knepley       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
577a8ad634aSStefano Zampini     } else v = originalv;
578a8ad634aSStefano Zampini   } else v = originalv;
579a8ad634aSStefano Zampini 
580d930f514SMatthew G. Knepley   if (ishdf5) {
581d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
5829566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
583d930f514SMatthew G. Knepley #else
584d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
585d930f514SMatthew G. Knepley #endif
586d930f514SMatthew G. Knepley   } else if (isvtk) {
587d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
588d930f514SMatthew G. Knepley   } else {
589d930f514SMatthew G. Knepley     PetscBool isseq;
590d930f514SMatthew G. Knepley 
5919566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq));
5929566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
5939566063dSJacob Faibussowitsch     else       PetscCall(VecView_MPI(v, viewer));
594d930f514SMatthew G. Knepley   }
5959566063dSJacob Faibussowitsch   if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v));
596d930f514SMatthew G. Knepley   PetscFunctionReturn(0);
597d930f514SMatthew G. Knepley }
598d930f514SMatthew G. Knepley 
5992c40f234SMatthew G. Knepley PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
6002c40f234SMatthew G. Knepley {
6012c40f234SMatthew G. Knepley   DM             dm;
6022c40f234SMatthew G. Knepley   PetscBool      ishdf5;
6032c40f234SMatthew G. Knepley 
6042c40f234SMatthew G. Knepley   PetscFunctionBegin;
6059566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
60628b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
6082c40f234SMatthew G. Knepley   if (ishdf5) {
6092c40f234SMatthew G. Knepley     DM          dmBC;
6102c40f234SMatthew G. Knepley     Vec         gv;
6112c40f234SMatthew G. Knepley     const char *name;
6122c40f234SMatthew G. Knepley 
6139566063dSJacob Faibussowitsch     PetscCall(DMGetOutputDM(dm, &dmBC));
6149566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmBC, &gv));
6159566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) v, &name));
6169566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject) gv, name));
6179566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(gv, viewer));
6189566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
6199566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
6209566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
6211baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
6222c40f234SMatthew G. Knepley   PetscFunctionReturn(0);
6232c40f234SMatthew G. Knepley }
6242c40f234SMatthew G. Knepley 
6252c40f234SMatthew G. Knepley PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
6262c40f234SMatthew G. Knepley {
6272c40f234SMatthew G. Knepley   DM             dm;
6286823f3c5SBlaise Bourdin   PetscBool      ishdf5,isexodusii;
6292c40f234SMatthew G. Knepley 
6302c40f234SMatthew G. Knepley   PetscFunctionBegin;
6319566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
63228b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
6349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii));
6352c40f234SMatthew G. Knepley   if (ishdf5) {
636878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6379566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
638b136c2c9SMatthew G. Knepley #else
639b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
640878b459fSMatthew G. Knepley #endif
6416823f3c5SBlaise Bourdin   } else if (isexodusii) {
6426823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
6439566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
6446823f3c5SBlaise Bourdin #else
6456823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
6466823f3c5SBlaise Bourdin #endif
6471baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
648552f7358SJed Brown   PetscFunctionReturn(0);
649552f7358SJed Brown }
650552f7358SJed Brown 
651d930f514SMatthew G. Knepley PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
652d930f514SMatthew G. Knepley {
653d930f514SMatthew G. Knepley   DM                dm;
654d930f514SMatthew G. Knepley   PetscViewerFormat format;
655d930f514SMatthew G. Knepley   PetscBool         ishdf5;
656d930f514SMatthew G. Knepley 
657d930f514SMatthew G. Knepley   PetscFunctionBegin;
6589566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
65928b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6609566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
6619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
662d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
663a8ad634aSStefano Zampini     if (dm->useNatural) {
664d930f514SMatthew G. Knepley       if (dm->sfNatural) {
665d930f514SMatthew G. Knepley         if (ishdf5) {
666d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
667d930f514SMatthew G. Knepley           Vec         v;
668d930f514SMatthew G. Knepley           const char *vecname;
669d930f514SMatthew G. Knepley 
6709566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalVector(dm, &v));
6719566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname));
6729566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject) v, vecname));
6739566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
6749566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
6759566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
6769566063dSJacob Faibussowitsch           PetscCall(DMRestoreGlobalVector(dm, &v));
677d930f514SMatthew G. Knepley #else
678d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
679d930f514SMatthew G. Knepley #endif
680d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
681d930f514SMatthew G. Knepley       }
6821baa6e33SBarry Smith     } else PetscCall(VecLoad_Default(originalv, viewer));
683d930f514SMatthew G. Knepley   }
684d930f514SMatthew G. Knepley   PetscFunctionReturn(0);
685d930f514SMatthew G. Knepley }
686d930f514SMatthew G. Knepley 
6877cd05799SMatthew G. Knepley PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
688731e8ddeSMatthew G. Knepley {
689731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
690731e8ddeSMatthew G. Knepley   Vec                coordinates;
691ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
692731e8ddeSMatthew G. Knepley   const char        *name[4];
693731e8ddeSMatthew G. Knepley   const PetscScalar *a;
694731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
695731e8ddeSMatthew G. Knepley 
696731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
6979566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
6989566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
6999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
7019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
7029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
7049566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
705731e8ddeSMatthew G. Knepley   name[0]     = "vertex";
706731e8ddeSMatthew G. Knepley   name[1]     = "edge";
707731e8ddeSMatthew G. Knepley   name[dim-1] = "face";
708731e8ddeSMatthew G. Knepley   name[dim]   = "cell";
709731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
710731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
711ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
712731e8ddeSMatthew G. Knepley 
7139566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
71463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
7159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7169566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
717731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
718731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
719731e8ddeSMatthew G. Knepley 
720731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
7219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
722731e8ddeSMatthew G. Knepley       if (!dof) continue;
7239566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
7249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
72563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
726731e8ddeSMatthew G. Knepley       for (p = 0; p < dof/dim; ++p) {
7279566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
728731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
7299566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
7309566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d])));
731731e8ddeSMatthew G. Knepley         }
7329566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
733731e8ddeSMatthew G. Knepley       }
7349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
735731e8ddeSMatthew G. Knepley     }
7369566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7379566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
738731e8ddeSMatthew G. Knepley   }
7399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
740731e8ddeSMatthew G. Knepley   PetscFunctionReturn(0);
741731e8ddeSMatthew G. Knepley }
742731e8ddeSMatthew G. Knepley 
74319ad8254SMatthew G. Knepley typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem;
74419ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
74519ad8254SMatthew G. Knepley 
74619ad8254SMatthew G. Knepley static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
74719ad8254SMatthew G. Knepley {
74819ad8254SMatthew G. Knepley   PetscInt       i;
74919ad8254SMatthew G. Knepley 
75019ad8254SMatthew G. Knepley   PetscFunctionBegin;
75119ad8254SMatthew G. Knepley   if (dim > 3) {
7529566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i])));
75319ad8254SMatthew G. Knepley   } else {
754bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
75519ad8254SMatthew G. Knepley 
75619ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
75719ad8254SMatthew G. Knepley     switch (cs) {
75819ad8254SMatthew G. Knepley       case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break;
75919ad8254SMatthew G. Knepley       case CS_POLAR:
76063a3b9bcSJacob Faibussowitsch         PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
76119ad8254SMatthew G. Knepley         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
76219ad8254SMatthew G. Knepley         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
76319ad8254SMatthew G. Knepley         break;
76419ad8254SMatthew G. Knepley       case CS_CYLINDRICAL:
76563a3b9bcSJacob Faibussowitsch         PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
76619ad8254SMatthew G. Knepley         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
76719ad8254SMatthew G. Knepley         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
76819ad8254SMatthew G. Knepley         trcoords[2] = coords[2];
76919ad8254SMatthew G. Knepley         break;
77019ad8254SMatthew G. Knepley       case CS_SPHERICAL:
77163a3b9bcSJacob Faibussowitsch         PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
77219ad8254SMatthew G. Knepley         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
77319ad8254SMatthew G. Knepley         trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
77419ad8254SMatthew G. Knepley         trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
77519ad8254SMatthew G. Knepley         break;
77619ad8254SMatthew G. Knepley     }
7779566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i]));
77819ad8254SMatthew G. Knepley   }
77919ad8254SMatthew G. Knepley   PetscFunctionReturn(0);
78019ad8254SMatthew G. Knepley }
78119ad8254SMatthew G. Knepley 
7827cd05799SMatthew G. Knepley static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
783552f7358SJed Brown {
784552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex*) dm->data;
7856858538eSMatthew G. Knepley   DM                cdm, cdmCell;
7866858538eSMatthew G. Knepley   PetscSection      coordSection, coordSectionCell;
7876858538eSMatthew G. Knepley   Vec               coordinates, coordinatesCell;
788552f7358SJed Brown   PetscViewerFormat format;
789552f7358SJed Brown 
790552f7358SJed Brown   PetscFunctionBegin;
7919566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
7926858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7939566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
7946858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
7956858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
7966858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
7979566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
798552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
799552f7358SJed Brown     const char *name;
800f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
8019318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
802552f7358SJed Brown     PetscMPIInt rank, size;
803552f7358SJed Brown 
8049566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
8059566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
8069566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
8079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
8099566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
8109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
81163a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
81263a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
81363a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
81463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
8159566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
81663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
817552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
818552f7358SJed Brown       PetscInt dof, off, s;
819552f7358SJed Brown 
8209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
822552f7358SJed Brown       for (s = off; s < off+dof; ++s) {
82363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
824552f7358SJed Brown       }
825552f7358SJed Brown     }
8269566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
82763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
82863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
829552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
830552f7358SJed Brown       PetscInt dof, off, c;
831552f7358SJed Brown 
8329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
8339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
834552f7358SJed Brown       for (c = off; c < off+dof; ++c) {
83563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
836552f7358SJed Brown       }
837552f7358SJed Brown     }
8389566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
8399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8403d2e540fSStefano Zampini     if (coordSection && coordinates) {
84119ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
8426858538eSMatthew G. Knepley       const PetscScalar *array, *arrayCell = NULL;
8436858538eSMatthew G. Knepley       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
84419ad8254SMatthew G. Knepley       PetscMPIInt        rank;
84519ad8254SMatthew G. Knepley       const char        *name;
84619ad8254SMatthew G. Knepley 
8479566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL));
8489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
8499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
85063a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
8519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
8526858538eSMatthew G. Knepley       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
8536858538eSMatthew G. Knepley       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
8546858538eSMatthew G. Knepley       pStart =  PetscMin(pvStart, pcStart);
8556858538eSMatthew G. Knepley       pEnd   =  PetscMax(pvEnd,   pcEnd);
8569566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject) coordinates, &name));
85763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
85863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
8599566063dSJacob Faibussowitsch       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
86019ad8254SMatthew G. Knepley 
8619566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordinates, &array));
8626858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
8639566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8649566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
86519ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
86619ad8254SMatthew G. Knepley         PetscInt dof, off;
86719ad8254SMatthew G. Knepley 
8686858538eSMatthew G. Knepley         if (p >= pvStart && p < pvEnd) {
8699566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
8709566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
8716858538eSMatthew G. Knepley           if (dof) {
87263a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
8739566063dSJacob Faibussowitsch             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
8749566063dSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
87519ad8254SMatthew G. Knepley           }
8766858538eSMatthew G. Knepley         }
8776858538eSMatthew G. Knepley         if (cdmCell && p >= pcStart && p < pcEnd) {
8786858538eSMatthew G. Knepley           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
8796858538eSMatthew G. Knepley           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
8806858538eSMatthew G. Knepley           if (dof) {
8816858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
8826858538eSMatthew G. Knepley             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
8836858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
8846858538eSMatthew G. Knepley           }
8856858538eSMatthew G. Knepley         }
8866858538eSMatthew G. Knepley       }
8879566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
8889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8899566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
8906858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
8913d2e540fSStefano Zampini     }
8929566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
8939566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
8949318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
8959318fe57SMatthew G. Knepley       DMLabel     label;
8969318fe57SMatthew G. Knepley       PetscBool   isdepth;
8979318fe57SMatthew G. Knepley       const char *name;
8989318fe57SMatthew G. Knepley 
8999566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
9009566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
9019318fe57SMatthew G. Knepley       if (isdepth) continue;
9029566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
9039566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
9049318fe57SMatthew G. Knepley     }
905552f7358SJed Brown     if (size > 1) {
906552f7358SJed Brown       PetscSF sf;
907552f7358SJed Brown 
9089566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
9099566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
910552f7358SJed Brown     }
9119566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
912552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
9130588280cSMatthew G. Knepley     const char  *name, *color;
9140588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
9150588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
916fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
917552f7358SJed Brown     PetscReal    scale         = 2.0;
91878081901SStefano Zampini     PetscReal    tikzscale     = 1.0;
919b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers    = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
9200588280cSMatthew G. Knepley     double       tcoords[3];
921552f7358SJed Brown     PetscScalar *coords;
922b7f6ffafSMatthew G. Knepley     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
923552f7358SJed Brown     PetscMPIInt  rank, size;
9240588280cSMatthew G. Knepley     char         **names, **colors, **lcolors;
925b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
926fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
927fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
928552f7358SJed Brown 
9299566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
9319566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
9320588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
9330588280cSMatthew G. Knepley     numColors  = 10;
9340588280cSMatthew G. Knepley     numLColors = 10;
9359566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
9369566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
9379566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
9389566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
939b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
940b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d]  = PETSC_TRUE;
941b7f6ffafSMatthew G. Knepley     n = 4;
9429566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
9431dca8a05SBarry 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);
9449566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
9451dca8a05SBarry 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);
9469566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
9470588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
9489566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
9490588280cSMatthew G. Knepley     if (!useColors) {
9500588280cSMatthew G. Knepley       numColors = 3;
9519566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
9520588280cSMatthew G. Knepley     }
9539566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
9540588280cSMatthew G. Knepley     if (!useColors) {
9550588280cSMatthew G. Knepley       numLColors = 4;
9569566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
9570588280cSMatthew G. Knepley     }
9589566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
959b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
9609566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
9611dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
962202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
9639566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
964fe1cc32dSStefano Zampini 
965fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
9669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
970fe1cc32dSStefano Zampini     if (lflg) {
971fe1cc32dSStefano Zampini       DMLabel lbl;
972fe1cc32dSStefano Zampini 
9739566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
974fe1cc32dSStefano Zampini       if (lbl) {
975fe1cc32dSStefano Zampini         PetscInt val, defval;
976fe1cc32dSStefano Zampini 
9779566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
9789566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd-pStart, &wp));
979fe1cc32dSStefano Zampini         for (c = pStart;  c < pEnd; c++) {
980fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
981fe1cc32dSStefano Zampini           PetscInt  closureSize;
982fe1cc32dSStefano Zampini 
9839566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
984fe1cc32dSStefano Zampini           if (val == defval) continue;
985fe1cc32dSStefano Zampini 
9869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
987fe1cc32dSStefano Zampini           for (p = 0; p < closureSize*2; p += 2) {
9889566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(wp, closure[p] - pStart));
989fe1cc32dSStefano Zampini           }
9909566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
991fe1cc32dSStefano Zampini         }
992fe1cc32dSStefano Zampini       }
993fe1cc32dSStefano Zampini     }
994fe1cc32dSStefano Zampini 
9959566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
9969566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
9979566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
9989566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
9990588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
1000552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
1001552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
1002552f7358SJed Brown \\usetikzlibrary{arrows}\n\
10035f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
10040588280cSMatthew G. Knepley     if (size > 1) {
10059566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1006770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
100763a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " :  ", "));
100863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p));
1009770b213bSMatthew G Knepley       }
10109566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
10110588280cSMatthew G. Knepley     }
1012b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1013b7f6ffafSMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart));
1014b7f6ffafSMatthew G. Knepley 
101563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
101663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1));
101763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart));
10189566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.));
101963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
102063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1));
10219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.));
102263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart));
102363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
102463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1));
102563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart));
10269566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.));
1027b7f6ffafSMatthew G. Knepley     }
10289566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale));
1029fe1cc32dSStefano Zampini 
1030552f7358SJed Brown     /* Plot vertices */
10319566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
10329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1033552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1034552f7358SJed Brown       PetscInt  off, dof, d;
10350588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1036552f7358SJed Brown 
1037fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
10389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
10399566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
10409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
104163a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof);
10420588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
10430588280cSMatthew G. Knepley         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1044c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
10450588280cSMatthew G. Knepley       }
10460588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
10470588280cSMatthew G. Knepley       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1048552f7358SJed Brown       for (d = 0; d < dof; ++d) {
10499566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
10509566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]));
1051552f7358SJed Brown       }
1052b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0%numColors];
1053b7f6ffafSMatthew G. Knepley       else           color = colors[rank%numColors];
10540588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
10550588280cSMatthew G. Knepley         PetscInt val;
10569566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
10570588280cSMatthew G. Knepley         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
10580588280cSMatthew G. Knepley       }
1059b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
106063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1061b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
106263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
10631baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1064552f7358SJed Brown     }
10659566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
10669566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1067b7f6ffafSMatthew G. Knepley     /* Plot edges */
1068b7f6ffafSMatthew G. Knepley     if (plotEdges) {
10699566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
10709566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1071b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1072b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1073b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1074b7f6ffafSMatthew G. Knepley 
1075b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
10769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
107763a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
10789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
10799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
10809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
10819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
10829566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1083b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1084b7f6ffafSMatthew G. Knepley           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
1085b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1086b7f6ffafSMatthew G. Knepley         }
1087b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1088b7f6ffafSMatthew G. Knepley         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1089b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
10909566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
10919566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1092b7f6ffafSMatthew G. Knepley         }
1093b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1%numColors];
1094b7f6ffafSMatthew G. Knepley         else           color = colors[rank%numColors];
1095b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1096b7f6ffafSMatthew G. Knepley           PetscInt val;
10979566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1098b7f6ffafSMatthew G. Knepley           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1099b7f6ffafSMatthew G. Knepley         }
110063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1101b7f6ffafSMatthew G. Knepley       }
11029566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
11039566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
11049566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1105b7f6ffafSMatthew G. Knepley     }
1106846a3e8bSMatthew G. Knepley     /* Plot cells */
1107b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1108846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1109846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1110846a3e8bSMatthew G. Knepley 
1111fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1112846a3e8bSMatthew G. Knepley         color = colors[rank%numColors];
1113846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1114846a3e8bSMatthew G. Knepley           PetscInt val;
11159566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1116846a3e8bSMatthew G. Knepley           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1117846a3e8bSMatthew G. Knepley         }
11189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
111963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1120846a3e8bSMatthew G. Knepley       }
1121846a3e8bSMatthew G. Knepley     } else {
1122b7f6ffafSMatthew G. Knepley        DMPolytopeType ct;
1123846a3e8bSMatthew G. Knepley 
1124b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1125b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1126fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
11279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
1128b7f6ffafSMatthew G. Knepley         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR ||
1129b7f6ffafSMatthew G. Knepley             ct == DM_POLYTOPE_TRI_PRISM_TENSOR ||
1130b7f6ffafSMatthew G. Knepley             ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1131b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1132b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1133b7f6ffafSMatthew G. Knepley 
11349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
11359566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1136b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1137b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1138b7f6ffafSMatthew G. Knepley 
11399566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
114063a3b9bcSJacob 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));
1141b7f6ffafSMatthew G. Knepley           }
1142b7f6ffafSMatthew G. Knepley         } else {
1143b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1144b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1145b7f6ffafSMatthew G. Knepley 
11469566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1147846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize*2; p += 2) {
1148846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1149846a3e8bSMatthew G. Knepley 
1150b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1151846a3e8bSMatthew G. Knepley           }
11529566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]));
1153b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1154b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v%Nv];
1155b7f6ffafSMatthew G. Knepley 
1156b7f6ffafSMatthew G. Knepley             if (v > 0) {
1157b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1158b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1159b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1160b7f6ffafSMatthew G. Knepley 
1161b7f6ffafSMatthew G. Knepley                 endpoints[0] = closure[v-1]; endpoints[1] = vertex;
11629566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
116363a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
116463a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
11659566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
11661baa6e33SBarry Smith               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1167b7f6ffafSMatthew G. Knepley             }
116863a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1169b7f6ffafSMatthew G. Knepley           }
11709566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
11719566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1172846a3e8bSMatthew G. Knepley         }
1173846a3e8bSMatthew G. Knepley       }
1174b7f6ffafSMatthew G. Knepley     }
11759566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
1176846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1177846a3e8bSMatthew G. Knepley       double    ccoords[3] = {0.0, 0.0, 0.0};
1178846a3e8bSMatthew G. Knepley       PetscBool isLabeled  = PETSC_FALSE;
1179846a3e8bSMatthew G. Knepley       PetscInt *closure    = NULL;
1180846a3e8bSMatthew G. Knepley       PetscInt  closureSize, dof, d, n = 0;
1181846a3e8bSMatthew G. Knepley 
1182fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
11839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
11849566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1185846a3e8bSMatthew G. Knepley       for (p = 0; p < closureSize*2; p += 2) {
1186846a3e8bSMatthew G. Knepley         const PetscInt point = closure[p];
1187846a3e8bSMatthew G. Knepley         PetscInt       off;
1188846a3e8bSMatthew G. Knepley 
1189846a3e8bSMatthew G. Knepley         if ((point < vStart) || (point >= vEnd)) continue;
11909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, point, &dof));
11919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, point, &off));
1192846a3e8bSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1193846a3e8bSMatthew G. Knepley           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1194846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1195846a3e8bSMatthew G. Knepley         }
1196846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1197846a3e8bSMatthew G. Knepley         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1198846a3e8bSMatthew G. Knepley         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
1199846a3e8bSMatthew G. Knepley         ++n;
1200846a3e8bSMatthew G. Knepley       }
1201846a3e8bSMatthew G. Knepley       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
12029566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1203846a3e8bSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
12049566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
12059566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]));
1206846a3e8bSMatthew G. Knepley       }
1207b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth%numColors];
1208b7f6ffafSMatthew G. Knepley       else           color = colors[rank%numColors];
1209846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1210846a3e8bSMatthew G. Knepley         PetscInt val;
12119566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
1212846a3e8bSMatthew G. Knepley         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1213846a3e8bSMatthew G. Knepley       }
1214b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
121563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1216b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
121763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
12181baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1219846a3e8bSMatthew G. Knepley     }
12209566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
1221b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1222b7f6ffafSMatthew G. Knepley       color = colors[depth%numColors];
12239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
12249566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
12259566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12269566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
12279566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1228552f7358SJed Brown 
1229b7f6ffafSMatthew G. Knepley       color = colors[1%numColors];
12309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
12319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
12329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
12349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1235b7f6ffafSMatthew G. Knepley 
1236b7f6ffafSMatthew G. Knepley       color = colors[0%numColors];
12379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
12389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
12399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
12419566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1242b7f6ffafSMatthew G. Knepley 
1243b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1244b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1245b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1246b7f6ffafSMatthew G. Knepley 
12479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
12489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1249b7f6ffafSMatthew G. Knepley         for (cp = 0; cp < coneSize; ++cp) {
125063a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1251552f7358SJed Brown         }
12520588280cSMatthew G. Knepley       }
12530588280cSMatthew G. Knepley     }
12549566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
12559566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
12569566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
125763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
12589566063dSJacob Faibussowitsch     for (l = 0; l < numLabels;  ++l) PetscCall(PetscFree(names[l]));
12599566063dSJacob Faibussowitsch     for (c = 0; c < numColors;  ++c) PetscCall(PetscFree(colors[c]));
12609566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
12619566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
12629566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
12630f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
12640f7d6e4aSStefano Zampini     Vec                    cown,acown;
12650f7d6e4aSStefano Zampini     VecScatter             sct;
12660f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
12670f7d6e4aSStefano Zampini     IS                     gid,acis;
12680f7d6e4aSStefano Zampini     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
12690f7d6e4aSStefano Zampini     MPI_Group              ggroup,ngroup;
12700f7d6e4aSStefano Zampini     PetscScalar            *array,nid;
12710f7d6e4aSStefano Zampini     const PetscInt         *idxs;
12720f7d6e4aSStefano Zampini     PetscInt               *idxs2,*start,*adjacency,*work;
12730f7d6e4aSStefano Zampini     PetscInt64             lm[3],gm[3];
12740f7d6e4aSStefano Zampini     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
12750f7d6e4aSStefano Zampini     PetscMPIInt            d1,d2,rank;
12760f7d6e4aSStefano Zampini 
12779566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
12789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm,&rank));
1279b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
12809566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm));
12810f7d6e4aSStefano Zampini #endif
12820f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
12839566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm,&ggroup));
12849566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm,&ngroup));
12850f7d6e4aSStefano Zampini       d1   = 0;
12869566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2));
12870f7d6e4aSStefano Zampini       nid  = d2;
12889566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
12899566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
12909566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
12910f7d6e4aSStefano Zampini     } else nid = 0.0;
12920f7d6e4aSStefano Zampini 
12930f7d6e4aSStefano Zampini     /* Get connectivity */
12949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight));
12959566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid));
12960f7d6e4aSStefano Zampini 
12970f7d6e4aSStefano Zampini     /* filter overlapped local cells */
12989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd));
12999566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid,&idxs));
13009566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid,&cum));
13019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum,&idxs2));
13020f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
13030f7d6e4aSStefano Zampini       if (idxs[c-cStart] < 0) continue;
13040f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c-cStart];
13050f7d6e4aSStefano Zampini     }
13069566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid,&idxs));
130763a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum);
13089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13099566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid));
13100f7d6e4aSStefano Zampini 
13110f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
13129566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis));
13139566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown));
13149566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown));
13159566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown,&array));
13160f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
13179566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown,&array));
13189566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct));
13199566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD));
13209566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD));
13219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
13229566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
13239566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
13240f7d6e4aSStefano Zampini 
13250f7d6e4aSStefano Zampini     /* compute edgeCut */
13260f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
13279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum,&work));
13289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l));
13299566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH));
13309566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13319566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown,&array));
13320f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
13330f7d6e4aSStefano Zampini       PetscInt totl;
13340f7d6e4aSStefano Zampini 
13350f7d6e4aSStefano Zampini       totl = start[c+1]-start[c];
13369566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work));
13370f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
13380f7d6e4aSStefano Zampini         if (work[i] < 0) {
13390f7d6e4aSStefano Zampini           ect  += 1;
13400f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
13410f7d6e4aSStefano Zampini         }
13420f7d6e4aSStefano Zampini       }
13430f7d6e4aSStefano Zampini     }
13449566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
13459566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown,&array));
13460f7d6e4aSStefano Zampini     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
13470f7d6e4aSStefano Zampini     lm[1] = -numVertices;
13481c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm));
134963a3b9bcSJacob 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]));
13500f7d6e4aSStefano Zampini     lm[0] = ect; /* edgeCut */
13510f7d6e4aSStefano Zampini     lm[1] = ectn; /* node-aware edgeCut */
13520f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
13531c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm));
135463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2]));
1355b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
135663a3b9bcSJacob 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.));
13570f7d6e4aSStefano Zampini #else
135863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0));
13590f7d6e4aSStefano Zampini #endif
13609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
13619566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
13629566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
13639566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1364552f7358SJed Brown   } else {
1365412e9a14SMatthew G. Knepley     const char    *name;
1366d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1367412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1368d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1369ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
13709318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1371412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1372412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1373552f7358SJed Brown 
13749566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
13759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
13769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
13779566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
13789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
13799566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
138063a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
138163a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
138263a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
13839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
13841c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
13859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd));
1386d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
13879566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
13889566063dSJacob Faibussowitsch     else                PetscCall(PetscCalloc3(3,    &sizes, 3,    &hybsizes, 3,    &ghostsizes));
1389412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1390412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1391412e9a14SMatthew G. Knepley 
13929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
13939566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1394412e9a14SMatthew G. Knepley       ict  = ct0;
13959566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1396412e9a14SMatthew G. Knepley       ct0  = (DMPolytopeType) ict;
1397412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1398412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1399412e9a14SMatthew G. Knepley 
14009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1401412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1402412e9a14SMatthew G. Knepley         else           ++Nc[1];
1403412e9a14SMatthew G. Knepley       }
1404ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
14059566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm));
14069566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
14079566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
140863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1409834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1410dd400576SPatrick Sanan           if (rank == 0) {
141163a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p]));
141263a3b9bcSJacob Faibussowitsch             if (hybsizes[p]   > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
141363a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1414834065abSMatthew G. Knepley           }
1415cbb7f117SMark Adams         }
1416ca7bf7eeSMatthew G. Knepley       } else {
1417ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1418ca7bf7eeSMatthew G. Knepley 
1419ca7bf7eeSMatthew G. Knepley         locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1];
14209566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1421ca7bf7eeSMatthew G. Knepley         locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1];
14229566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1423ca7bf7eeSMatthew G. Knepley         if (d == depth) {
1424ca7bf7eeSMatthew G. Knepley           locMinMax[0] = gcNum; locMinMax[1] = gcNum;
14259566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1426ca7bf7eeSMatthew G. Knepley         }
142763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
14289566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
14299566063dSJacob Faibussowitsch         if (hybsizes[0]   > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
14309566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1431ca7bf7eeSMatthew G. Knepley       }
14329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1433552f7358SJed Brown     }
14349566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
14359318fe57SMatthew G. Knepley     {
14369318fe57SMatthew G. Knepley       const PetscReal *maxCell;
14379318fe57SMatthew G. Knepley       const PetscReal *L;
14386858538eSMatthew G. Knepley       PetscBool        localized;
14399318fe57SMatthew G. Knepley 
1440*4fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
14419566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
14426858538eSMatthew G. Knepley       if (L || localized) {
14436858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
14449566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
14456858538eSMatthew G. Knepley         if (L) {
14466858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
14479318fe57SMatthew G. Knepley           for (d = 0; d < dim; ++d) {
14486858538eSMatthew G. Knepley             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
14496858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
14509318fe57SMatthew G. Knepley           }
14516858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
14526858538eSMatthew G. Knepley         }
14536858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
14549566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
14559318fe57SMatthew G. Knepley       }
14569318fe57SMatthew G. Knepley     }
14579566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
14589566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1459a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1460a57dd577SMatthew G Knepley       DMLabel         label;
1461a57dd577SMatthew G Knepley       const char     *name;
1462a57dd577SMatthew G Knepley       IS              valueIS;
1463a57dd577SMatthew G Knepley       const PetscInt *values;
1464a57dd577SMatthew G Knepley       PetscInt        numValues, v;
1465a57dd577SMatthew G Knepley 
14669566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
14679566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
14689566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
146963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
14709566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValueIS(label, &valueIS));
14719566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(valueIS, &values));
14729566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1473a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1474a57dd577SMatthew G Knepley         PetscInt size;
1475a57dd577SMatthew G Knepley 
14769566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
14779566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
147863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1479a57dd577SMatthew G Knepley       }
14809566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
14819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
14829566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(valueIS, &values));
14839566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&valueIS));
1484a57dd577SMatthew G Knepley     }
1485c1cad2e7SMatthew G. Knepley     {
1486c1cad2e7SMatthew G. Knepley       char    **labelNames;
1487c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1488c1cad2e7SMatthew G. Knepley       PetscBool flg;
1489c1cad2e7SMatthew G. Knepley 
14909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
14919566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1492c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1493c1cad2e7SMatthew G. Knepley         DMLabel label;
1494c1cad2e7SMatthew G. Knepley 
14959566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1496c1cad2e7SMatthew G. Knepley         if (flg) {
14979566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
14989566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1499c1cad2e7SMatthew G. Knepley         }
15009566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1501c1cad2e7SMatthew G. Knepley       }
15029566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1503c1cad2e7SMatthew G. Knepley     }
150434aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
150534aa8a36SMatthew G. Knepley     if (dm->Nf) {
150634aa8a36SMatthew G. Knepley       PetscInt f;
150734aa8a36SMatthew G. Knepley 
150834aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
150934aa8a36SMatthew G. Knepley         const char *name;
151034aa8a36SMatthew G. Knepley 
15119566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
15129566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
15139566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
15149566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
151534aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
15169566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
15179566063dSJacob Faibussowitsch           else                            PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
151834aa8a36SMatthew G. Knepley         } else {
15199566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
15209566063dSJacob Faibussowitsch           else                            PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
152134aa8a36SMatthew G. Knepley         }
15229566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
152334aa8a36SMatthew G. Knepley       }
152434aa8a36SMatthew G. Knepley     }
15259566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
15268e7ff633SMatthew G. Knepley     if (cdm) {
15279566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
15289566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
15299566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
15308e7ff633SMatthew G. Knepley     }
1531552f7358SJed Brown   }
1532552f7358SJed Brown   PetscFunctionReturn(0);
1533552f7358SJed Brown }
1534552f7358SJed Brown 
1535e5c487bfSMatthew G. Knepley static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1536e5c487bfSMatthew G. Knepley {
1537e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1538e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1539a12d352dSMatthew G. Knepley   PetscInt       cdim;
1540e5c487bfSMatthew G. Knepley 
1541e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
15429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
15439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
15449566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1545e5c487bfSMatthew G. Knepley   switch (ct) {
1546a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1547a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1548a12d352dSMatthew G. Knepley     switch (cdim) {
1549a12d352dSMatthew G. Knepley     case 1:
1550a12d352dSMatthew G. Knepley     {
1551a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1552a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1553a12d352dSMatthew G. Knepley 
15549566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y,    PetscRealPart(coords[1]), y,    PETSC_DRAW_BLACK));
15559566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK));
15569566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK));
1557a12d352dSMatthew G. Knepley     }
1558a12d352dSMatthew G. Knepley     break;
1559a12d352dSMatthew G. Knepley     case 2:
1560a12d352dSMatthew G. Knepley     {
1561a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1562a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1563a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1/PetscSqrtReal(dx*dx + dy*dy);
1564a12d352dSMatthew G. Knepley 
15659566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
15669566063dSJacob 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));
15679566063dSJacob 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));
1568a12d352dSMatthew G. Knepley     }
1569a12d352dSMatthew G. Knepley     break;
157063a3b9bcSJacob Faibussowitsch     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1571a12d352dSMatthew G. Knepley     }
1572a12d352dSMatthew G. Knepley     break;
1573e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
15749566063dSJacob Faibussowitsch     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1575e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1576e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
15775f80ce2aSJacob Faibussowitsch                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
15789566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
15799566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
15809566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1581e5c487bfSMatthew G. Knepley     break;
1582e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
15839566063dSJacob Faibussowitsch     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1584e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1585e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
15865f80ce2aSJacob Faibussowitsch                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
15879566063dSJacob Faibussowitsch     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1588e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1589e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
15905f80ce2aSJacob Faibussowitsch                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
15919566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
15929566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
15939566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
15949566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1595e5c487bfSMatthew G. Knepley     break;
159698921bdaSJacob Faibussowitsch   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1597e5c487bfSMatthew G. Knepley   }
1598e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
1599e5c487bfSMatthew G. Knepley }
1600e5c487bfSMatthew G. Knepley 
1601e5c487bfSMatthew G. Knepley static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1602e5c487bfSMatthew G. Knepley {
1603e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1604e5c487bfSMatthew G. Knepley   PetscReal      centroid[2] = {0., 0.};
1605e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1606e5c487bfSMatthew G. Knepley   PetscInt       fillColor, v, e, d;
1607e5c487bfSMatthew G. Knepley 
1608e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
16099566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
16109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1611e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1612e5c487bfSMatthew G. Knepley   switch (ct) {
1613e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
1614e5c487bfSMatthew G. Knepley     {
1615e5c487bfSMatthew G. Knepley       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1616e5c487bfSMatthew G. Knepley 
1617e5c487bfSMatthew G. Knepley       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1618e5c487bfSMatthew G. Knepley       for (e = 0; e < 3; ++e) {
1619e5c487bfSMatthew G. Knepley         refCoords[0] = refVertices[e*2+0];
1620e5c487bfSMatthew G. Knepley         refCoords[1] = refVertices[e*2+1];
1621e5c487bfSMatthew G. Knepley         for (d = 1; d <= edgeDiv; ++d) {
1622e5c487bfSMatthew G. Knepley           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1623e5c487bfSMatthew G. Knepley           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1624e5c487bfSMatthew G. Knepley         }
16259566063dSJacob Faibussowitsch         PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords));
1626e5c487bfSMatthew G. Knepley         for (d = 0; d < edgeDiv; ++d) {
16279566063dSJacob 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));
16289566063dSJacob 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));
1629e5c487bfSMatthew G. Knepley         }
1630e5c487bfSMatthew G. Knepley       }
1631e5c487bfSMatthew G. Knepley     }
1632e5c487bfSMatthew G. Knepley     break;
163398921bdaSJacob Faibussowitsch   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1634e5c487bfSMatthew G. Knepley   }
1635e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
1636e5c487bfSMatthew G. Knepley }
1637e5c487bfSMatthew G. Knepley 
16387cd05799SMatthew G. Knepley static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1639e412dcbdSMatthew G. Knepley {
1640e412dcbdSMatthew G. Knepley   PetscDraw          draw;
1641e412dcbdSMatthew G. Knepley   DM                 cdm;
1642e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
1643e412dcbdSMatthew G. Knepley   Vec                coordinates;
1644e412dcbdSMatthew G. Knepley   const PetscScalar *coords;
164529494db1SLisandro Dalcin   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1646e5c487bfSMatthew G. Knepley   PetscReal         *refCoords, *edgeCoords;
1647e5c487bfSMatthew G. Knepley   PetscBool          isnull, drawAffine = PETSC_TRUE;
1648e5c487bfSMatthew G. Knepley   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1649e412dcbdSMatthew G. Knepley 
1650e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
16519566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
165263a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
16539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
16549566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords));
16559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
16569566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
16579566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
16589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
16599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1660e412dcbdSMatthew G. Knepley 
16619566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
16629566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
1663e412dcbdSMatthew G. Knepley   if (isnull) PetscFunctionReturn(0);
16649566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1665e412dcbdSMatthew G. Knepley 
16669566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
16679566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
1668e412dcbdSMatthew G. Knepley   for (c = 0; c < N; c += dim) {
16690c81f2a8SMatthew G. Knepley     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
16700c81f2a8SMatthew G. Knepley     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1671e412dcbdSMatthew G. Knepley   }
16729566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
16731c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm)));
16741c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm)));
16759566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
16769566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1677e412dcbdSMatthew G. Knepley 
1678cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1679cf3064d3SMatthew G. Knepley     PetscScalar *coords = NULL;
1680ba2698f1SMatthew G. Knepley     PetscInt     numCoords;
1681cf3064d3SMatthew G. Knepley 
16829566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords));
16831baa6e33SBarry Smith     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
16841baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
16859566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
1686cf3064d3SMatthew G. Knepley   }
16879566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
16889566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
16899566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
16909566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
1691e412dcbdSMatthew G. Knepley   PetscFunctionReturn(0);
1692e412dcbdSMatthew G. Knepley }
1693e412dcbdSMatthew G. Knepley 
16941e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
16951e50132fSMatthew G. Knepley #include <exodusII.h>
16966823f3c5SBlaise Bourdin #include <petscviewerexodusii.h>
16971e50132fSMatthew G. Knepley #endif
16981e50132fSMatthew G. Knepley 
1699552f7358SJed Brown PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1700552f7358SJed Brown {
17011e50132fSMatthew G. Knepley   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1702002a2709SMatthew G. Knepley   char           name[PETSC_MAX_PATH_LEN];
1703552f7358SJed Brown 
1704552f7358SJed Brown   PetscFunctionBegin;
1705552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1706552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
17079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii));
17089566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk));
17099566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
17109566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw));
17119566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis));
17129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus));
1713552f7358SJed Brown   if (iascii) {
17148135c375SStefano Zampini     PetscViewerFormat format;
17159566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
17161baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
17171baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
1718c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1719c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
17209566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1721c6ccd67eSMatthew G. Knepley #else
1722c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1723552f7358SJed Brown #endif
1724e412dcbdSMatthew G. Knepley   } else if (isvtk) {
17259566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer));
1726e412dcbdSMatthew G. Knepley   } else if (isdraw) {
17279566063dSJacob Faibussowitsch     PetscCall(DMPlexView_Draw(dm, viewer));
17288135c375SStefano Zampini   } else if (isglvis) {
17299566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
17301e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
17311e50132fSMatthew G. Knepley   } else if (isexodus) {
17326823f3c5SBlaise Bourdin /*
17336823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
17346823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
17356823f3c5SBlaise Bourdin       with ID 1, containig all cells.
17366823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
17376823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
17386823f3c5SBlaise Bourdin     */
17396823f3c5SBlaise Bourdin     PetscInt numCS;
17409566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS));
17416823f3c5SBlaise Bourdin     if (!numCS) {
17421e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
17439566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
17449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
17459566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
17466823f3c5SBlaise Bourdin     }
17479566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
17481e50132fSMatthew G. Knepley #endif
17491baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
17501baa6e33SBarry Smith 
1751cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
17529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg));
1753cb3ba0daSMatthew G. Knepley   if (flg) {
1754cb3ba0daSMatthew G. Knepley     Vec ranks;
17559566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
17569566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
17579566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
1758cb3ba0daSMatthew G. Knepley   }
1759002a2709SMatthew G. Knepley   /* Optionally view a label */
17609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1761002a2709SMatthew G. Knepley   if (flg) {
1762002a2709SMatthew G. Knepley     DMLabel label;
1763002a2709SMatthew G. Knepley     Vec     val;
1764002a2709SMatthew G. Knepley 
17659566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
176628b400f6SJacob Faibussowitsch     PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
17679566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
17689566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
17699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
1770002a2709SMatthew G. Knepley   }
1771552f7358SJed Brown   PetscFunctionReturn(0);
1772552f7358SJed Brown }
1773552f7358SJed Brown 
17747f96f51bSksagiyam /*@
17757f96f51bSksagiyam   DMPlexTopologyView - Saves a DMPlex topology into a file
17767f96f51bSksagiyam 
17777f96f51bSksagiyam   Collective on DM
17787f96f51bSksagiyam 
17797f96f51bSksagiyam   Input Parameters:
17807f96f51bSksagiyam + dm     - The DM whose topology is to be saved
17817f96f51bSksagiyam - viewer - The PetscViewer for saving
17827f96f51bSksagiyam 
17837f96f51bSksagiyam   Level: advanced
17847f96f51bSksagiyam 
1785db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`
17867f96f51bSksagiyam @*/
17877f96f51bSksagiyam PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
17887f96f51bSksagiyam {
17897f96f51bSksagiyam   PetscBool      ishdf5;
17907f96f51bSksagiyam 
17917f96f51bSksagiyam   PetscFunctionBegin;
17927f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
17937f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
17949566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
17959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0));
17967f96f51bSksagiyam   if (ishdf5) {
17977f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
17987f96f51bSksagiyam     PetscViewerFormat format;
17999566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
18007f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18017f96f51bSksagiyam       IS globalPointNumbering;
18027f96f51bSksagiyam 
18039566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
18049566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
18059566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
180698921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
18077f96f51bSksagiyam #else
18087f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
18097f96f51bSksagiyam #endif
18107f96f51bSksagiyam   }
18119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0));
18127f96f51bSksagiyam   PetscFunctionReturn(0);
18137f96f51bSksagiyam }
18147f96f51bSksagiyam 
181577b8e257Sksagiyam /*@
181677b8e257Sksagiyam   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
181777b8e257Sksagiyam 
181877b8e257Sksagiyam   Collective on DM
181977b8e257Sksagiyam 
182077b8e257Sksagiyam   Input Parameters:
182177b8e257Sksagiyam + dm     - The DM whose coordinates are to be saved
182277b8e257Sksagiyam - viewer - The PetscViewer for saving
182377b8e257Sksagiyam 
182477b8e257Sksagiyam   Level: advanced
182577b8e257Sksagiyam 
1826db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`
182777b8e257Sksagiyam @*/
182877b8e257Sksagiyam PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
182977b8e257Sksagiyam {
183077b8e257Sksagiyam   PetscBool      ishdf5;
183177b8e257Sksagiyam 
183277b8e257Sksagiyam   PetscFunctionBegin;
183377b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
183477b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
18369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0));
183777b8e257Sksagiyam   if (ishdf5) {
183877b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
183977b8e257Sksagiyam     PetscViewerFormat format;
18409566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
184177b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18429566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
184398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
184477b8e257Sksagiyam #else
184577b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
184677b8e257Sksagiyam #endif
184777b8e257Sksagiyam   }
18489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0));
184977b8e257Sksagiyam   PetscFunctionReturn(0);
185077b8e257Sksagiyam }
185177b8e257Sksagiyam 
1852bd6565f1Sksagiyam /*@
1853bd6565f1Sksagiyam   DMPlexLabelsView - Saves DMPlex labels into a file
1854bd6565f1Sksagiyam 
1855bd6565f1Sksagiyam   Collective on DM
1856bd6565f1Sksagiyam 
1857bd6565f1Sksagiyam   Input Parameters:
1858bd6565f1Sksagiyam + dm     - The DM whose labels are to be saved
1859bd6565f1Sksagiyam - viewer - The PetscViewer for saving
1860bd6565f1Sksagiyam 
1861bd6565f1Sksagiyam   Level: advanced
1862bd6565f1Sksagiyam 
1863db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`
1864bd6565f1Sksagiyam @*/
1865bd6565f1Sksagiyam PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1866bd6565f1Sksagiyam {
1867bd6565f1Sksagiyam   PetscBool      ishdf5;
1868bd6565f1Sksagiyam 
1869bd6565f1Sksagiyam   PetscFunctionBegin;
1870bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1871bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
18739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0));
1874bd6565f1Sksagiyam   if (ishdf5) {
1875bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
1876bd6565f1Sksagiyam     IS                globalPointNumbering;
1877bd6565f1Sksagiyam     PetscViewerFormat format;
1878bd6565f1Sksagiyam 
18799566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
1880bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18819566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
18829566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
18839566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
188498921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1885bd6565f1Sksagiyam #else
1886bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1887bd6565f1Sksagiyam #endif
1888bd6565f1Sksagiyam   }
18899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0));
1890bd6565f1Sksagiyam   PetscFunctionReturn(0);
1891bd6565f1Sksagiyam }
1892bd6565f1Sksagiyam 
1893021affd3Sksagiyam /*@
1894021affd3Sksagiyam   DMPlexSectionView - Saves a section associated with a DMPlex
1895021affd3Sksagiyam 
1896021affd3Sksagiyam   Collective on DM
1897021affd3Sksagiyam 
1898021affd3Sksagiyam   Input Parameters:
1899021affd3Sksagiyam + dm         - The DM that contains the topology on which the section to be saved is defined
1900021affd3Sksagiyam . viewer     - The PetscViewer for saving
1901021affd3Sksagiyam - sectiondm  - The DM that contains the section to be saved
1902021affd3Sksagiyam 
1903021affd3Sksagiyam   Level: advanced
1904021affd3Sksagiyam 
1905021affd3Sksagiyam   Notes:
1906021affd3Sksagiyam   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.
1907021affd3Sksagiyam 
1908021affd3Sksagiyam   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.
1909021affd3Sksagiyam 
1910db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`
1911021affd3Sksagiyam @*/
1912021affd3Sksagiyam PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1913021affd3Sksagiyam {
1914021affd3Sksagiyam   PetscBool      ishdf5;
1915021affd3Sksagiyam 
1916021affd3Sksagiyam   PetscFunctionBegin;
1917021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1918021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1919021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
19209566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
19219566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0));
1922021affd3Sksagiyam   if (ishdf5) {
1923021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
19249566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1925021affd3Sksagiyam #else
1926021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1927021affd3Sksagiyam #endif
1928021affd3Sksagiyam   }
19299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0));
1930021affd3Sksagiyam   PetscFunctionReturn(0);
1931021affd3Sksagiyam }
1932021affd3Sksagiyam 
19333e97647fSksagiyam /*@
19343e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
19353e97647fSksagiyam 
19363e97647fSksagiyam   Collective on DM
19373e97647fSksagiyam 
19383e97647fSksagiyam   Input Parameters:
19393e97647fSksagiyam + dm        - The DM that represents the topology
19403e97647fSksagiyam . viewer    - The PetscViewer to save data with
19413e97647fSksagiyam . sectiondm - The DM that contains the global section on which vec is defined
19423e97647fSksagiyam - vec       - The global vector to be saved
19433e97647fSksagiyam 
19443e97647fSksagiyam   Level: advanced
19453e97647fSksagiyam 
19463e97647fSksagiyam   Notes:
19473e97647fSksagiyam   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.
19483e97647fSksagiyam 
19493e97647fSksagiyam   Typical calling sequence
19503e97647fSksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
19513e97647fSksagiyam $       DMSetType(dm, DMPLEX);
19523e97647fSksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
19533e97647fSksagiyam $       DMClone(dm, &sectiondm);
19543e97647fSksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
19553e97647fSksagiyam $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
19563e97647fSksagiyam $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
19573e97647fSksagiyam $       PetscSectionSetChart(section, pStart, pEnd);
19583e97647fSksagiyam $       PetscSectionSetUp(section);
19593e97647fSksagiyam $       DMSetLocalSection(sectiondm, section);
19603e97647fSksagiyam $       PetscSectionDestroy(&section);
19613e97647fSksagiyam $       DMGetGlobalVector(sectiondm, &vec);
19623e97647fSksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
19633e97647fSksagiyam $       DMPlexTopologyView(dm, viewer);
19643e97647fSksagiyam $       DMPlexSectionView(dm, viewer, sectiondm);
19653e97647fSksagiyam $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
19663e97647fSksagiyam $       DMRestoreGlobalVector(sectiondm, &vec);
19673e97647fSksagiyam $       DMDestroy(&sectiondm);
19683e97647fSksagiyam $       DMDestroy(&dm);
19693e97647fSksagiyam 
1970db781477SPatrick Sanan .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
19713e97647fSksagiyam @*/
19723e97647fSksagiyam PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
19733e97647fSksagiyam {
19743e97647fSksagiyam   PetscBool       ishdf5;
19753e97647fSksagiyam 
19763e97647fSksagiyam   PetscFunctionBegin;
19773e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19783e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19793e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
19803e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
19813e97647fSksagiyam   /* Check consistency */
19823e97647fSksagiyam   {
19833e97647fSksagiyam     PetscSection  section;
19843e97647fSksagiyam     PetscBool     includesConstraints;
19853e97647fSksagiyam     PetscInt      m, m1;
19863e97647fSksagiyam 
19879566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
19889566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
19899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
19909566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
19919566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
199263a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
19933e97647fSksagiyam   }
19949566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0));
19963e97647fSksagiyam   if (ishdf5) {
19973e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
19989566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
19993e97647fSksagiyam #else
20003e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20013e97647fSksagiyam #endif
20023e97647fSksagiyam   }
20039566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0));
20043e97647fSksagiyam   PetscFunctionReturn(0);
20053e97647fSksagiyam }
20063e97647fSksagiyam 
20073e97647fSksagiyam /*@
20083e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
20093e97647fSksagiyam 
20103e97647fSksagiyam   Collective on DM
20113e97647fSksagiyam 
20123e97647fSksagiyam   Input Parameters:
20133e97647fSksagiyam + dm        - The DM that represents the topology
20143e97647fSksagiyam . viewer    - The PetscViewer to save data with
20153e97647fSksagiyam . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
20163e97647fSksagiyam - vec       - The local vector to be saved
20173e97647fSksagiyam 
20183e97647fSksagiyam   Level: advanced
20193e97647fSksagiyam 
20203e97647fSksagiyam   Notes:
20213e97647fSksagiyam   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.
20223e97647fSksagiyam 
20233e97647fSksagiyam   Typical calling sequence
20243e97647fSksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
20253e97647fSksagiyam $       DMSetType(dm, DMPLEX);
20263e97647fSksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
20273e97647fSksagiyam $       DMClone(dm, &sectiondm);
20283e97647fSksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
20293e97647fSksagiyam $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
20303e97647fSksagiyam $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
20313e97647fSksagiyam $       PetscSectionSetChart(section, pStart, pEnd);
20323e97647fSksagiyam $       PetscSectionSetUp(section);
20333e97647fSksagiyam $       DMSetLocalSection(sectiondm, section);
20343e97647fSksagiyam $       DMGetLocalVector(sectiondm, &vec);
20353e97647fSksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
20363e97647fSksagiyam $       DMPlexTopologyView(dm, viewer);
20373e97647fSksagiyam $       DMPlexSectionView(dm, viewer, sectiondm);
20383e97647fSksagiyam $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
20393e97647fSksagiyam $       DMRestoreLocalVector(sectiondm, &vec);
20403e97647fSksagiyam $       DMDestroy(&sectiondm);
20413e97647fSksagiyam $       DMDestroy(&dm);
20423e97647fSksagiyam 
2043db781477SPatrick Sanan .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
20443e97647fSksagiyam @*/
20453e97647fSksagiyam PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
20463e97647fSksagiyam {
20473e97647fSksagiyam   PetscBool       ishdf5;
20483e97647fSksagiyam 
20493e97647fSksagiyam   PetscFunctionBegin;
20503e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20513e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20523e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
20533e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
20543e97647fSksagiyam   /* Check consistency */
20553e97647fSksagiyam   {
20563e97647fSksagiyam     PetscSection  section;
20573e97647fSksagiyam     PetscBool     includesConstraints;
20583e97647fSksagiyam     PetscInt      m, m1;
20593e97647fSksagiyam 
20609566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
20619566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
20629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
20639566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
20649566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
206563a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
20663e97647fSksagiyam   }
20679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20689566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0));
20693e97647fSksagiyam   if (ishdf5) {
20703e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
20719566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
20723e97647fSksagiyam #else
20733e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20743e97647fSksagiyam #endif
20753e97647fSksagiyam   }
20769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0));
20773e97647fSksagiyam   PetscFunctionReturn(0);
20783e97647fSksagiyam }
20793e97647fSksagiyam 
20802c40f234SMatthew G. Knepley PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
20812c40f234SMatthew G. Knepley {
2082d4f5a9a0SVaclav Hapla   PetscBool      ishdf5;
20832c40f234SMatthew G. Knepley 
20842c40f234SMatthew G. Knepley   PetscFunctionBegin;
20852c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20862c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5));
2088d4f5a9a0SVaclav Hapla   if (ishdf5) {
20892c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
20909c48423bSVaclav Hapla     PetscViewerFormat format;
20919566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20929c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
20939566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2094509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20959566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
209698921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2097b458e8f1SJose E. Roman     PetscFunctionReturn(0);
20982c40f234SMatthew G. Knepley #else
20992c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2100552f7358SJed Brown #endif
210198921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2102552f7358SJed Brown }
2103552f7358SJed Brown 
2104ea8e1828Sksagiyam /*@
2105ea8e1828Sksagiyam   DMPlexTopologyLoad - Loads a topology into a DMPlex
2106ea8e1828Sksagiyam 
2107ea8e1828Sksagiyam   Collective on DM
2108ea8e1828Sksagiyam 
2109ea8e1828Sksagiyam   Input Parameters:
2110ea8e1828Sksagiyam + dm     - The DM into which the topology is loaded
2111ea8e1828Sksagiyam - viewer - The PetscViewer for the saved topology
2112ea8e1828Sksagiyam 
2113dec9e869Sksagiyam   Output Parameters:
2114f84dd6b4Sksagiyam . 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
2115dec9e869Sksagiyam 
2116ea8e1828Sksagiyam   Level: advanced
2117ea8e1828Sksagiyam 
2118db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
2119ea8e1828Sksagiyam @*/
2120f84dd6b4Sksagiyam PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2121ea8e1828Sksagiyam {
2122ea8e1828Sksagiyam   PetscBool      ishdf5;
2123ea8e1828Sksagiyam 
2124ea8e1828Sksagiyam   PetscFunctionBegin;
2125ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2126ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2127f84dd6b4Sksagiyam   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
21289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
21299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0));
2130ea8e1828Sksagiyam   if (ishdf5) {
2131ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2132ea8e1828Sksagiyam     PetscViewerFormat format;
21339566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2134ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21359566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
213698921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2137ea8e1828Sksagiyam #else
2138ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2139ea8e1828Sksagiyam #endif
2140ea8e1828Sksagiyam   }
21419566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0));
2142ea8e1828Sksagiyam   PetscFunctionReturn(0);
2143ea8e1828Sksagiyam }
2144ea8e1828Sksagiyam 
21453e701f1cSksagiyam /*@
21463e701f1cSksagiyam   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
21473e701f1cSksagiyam 
21483e701f1cSksagiyam   Collective on DM
21493e701f1cSksagiyam 
21503e701f1cSksagiyam   Input Parameters:
21513e701f1cSksagiyam + dm     - The DM into which the coordinates are loaded
2152c9ad657eSksagiyam . viewer - The PetscViewer for the saved coordinates
2153c9ad657eSksagiyam - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
21543e701f1cSksagiyam 
21553e701f1cSksagiyam   Level: advanced
21563e701f1cSksagiyam 
2157db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
21583e701f1cSksagiyam @*/
2159c9ad657eSksagiyam PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
21603e701f1cSksagiyam {
21613e701f1cSksagiyam   PetscBool      ishdf5;
21623e701f1cSksagiyam 
21633e701f1cSksagiyam   PetscFunctionBegin;
21643e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21653e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2166c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
21679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
21689566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0));
21693e701f1cSksagiyam   if (ishdf5) {
21703e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
21713e701f1cSksagiyam     PetscViewerFormat format;
21729566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
21733e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21749566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
217598921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
21763e701f1cSksagiyam #else
21773e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
21783e701f1cSksagiyam #endif
21793e701f1cSksagiyam   }
21809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0));
21813e701f1cSksagiyam   PetscFunctionReturn(0);
21823e701f1cSksagiyam }
21833e701f1cSksagiyam 
2184b08ad5deSksagiyam /*@
2185b08ad5deSksagiyam   DMPlexLabelsLoad - Loads labels into a DMPlex
2186b08ad5deSksagiyam 
2187b08ad5deSksagiyam   Collective on DM
2188b08ad5deSksagiyam 
2189b08ad5deSksagiyam   Input Parameters:
2190b08ad5deSksagiyam + dm     - The DM into which the labels are loaded
2191e6368b79SVaclav Hapla . viewer - The PetscViewer for the saved labels
2192e6368b79SVaclav Hapla - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2193b08ad5deSksagiyam 
2194b08ad5deSksagiyam   Level: advanced
2195b08ad5deSksagiyam 
2196e6368b79SVaclav Hapla   Notes:
2197e6368b79SVaclav Hapla   The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs.
2198e6368b79SVaclav Hapla 
2199db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
2200b08ad5deSksagiyam @*/
2201e6368b79SVaclav Hapla PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2202b08ad5deSksagiyam {
2203b08ad5deSksagiyam   PetscBool      ishdf5;
2204b08ad5deSksagiyam 
2205b08ad5deSksagiyam   PetscFunctionBegin;
2206b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2207b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2208e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
22099566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
22109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0));
2211b08ad5deSksagiyam   if (ishdf5) {
2212b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2213b08ad5deSksagiyam     PetscViewerFormat format;
2214b08ad5deSksagiyam 
22159566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2216b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
22179566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
221898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2219b08ad5deSksagiyam #else
2220b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2221b08ad5deSksagiyam #endif
2222b08ad5deSksagiyam   }
22239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0));
2224b08ad5deSksagiyam   PetscFunctionReturn(0);
2225b08ad5deSksagiyam }
2226b08ad5deSksagiyam 
2227f84dd6b4Sksagiyam /*@
2228f84dd6b4Sksagiyam   DMPlexSectionLoad - Loads section into a DMPlex
2229f84dd6b4Sksagiyam 
2230f84dd6b4Sksagiyam   Collective on DM
2231f84dd6b4Sksagiyam 
2232f84dd6b4Sksagiyam   Input Parameters:
2233f84dd6b4Sksagiyam + dm          - The DM that represents the topology
2234f84dd6b4Sksagiyam . viewer      - The PetscViewer that represents the on-disk section (sectionA)
2235f84dd6b4Sksagiyam . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2236f84dd6b4Sksagiyam - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2237f84dd6b4Sksagiyam 
2238f84dd6b4Sksagiyam   Output Parameters
2239f84dd6b4Sksagiyam + 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)
2240f84dd6b4Sksagiyam - 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)
2241f84dd6b4Sksagiyam 
2242f84dd6b4Sksagiyam   Level: advanced
2243f84dd6b4Sksagiyam 
2244f84dd6b4Sksagiyam   Notes:
2245f84dd6b4Sksagiyam   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.
2246f84dd6b4Sksagiyam 
2247f84dd6b4Sksagiyam   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.
2248f84dd6b4Sksagiyam 
2249f84dd6b4Sksagiyam   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.
2250f84dd6b4Sksagiyam 
2251f84dd6b4Sksagiyam   Example using 2 processes:
2252f84dd6b4Sksagiyam $  NX (number of points on dm): 4
2253f84dd6b4Sksagiyam $  sectionA                   : the on-disk section
2254f84dd6b4Sksagiyam $  vecA                       : a vector associated with sectionA
2255f84dd6b4Sksagiyam $  sectionB                   : sectiondm's local section constructed in this function
2256f84dd6b4Sksagiyam $  vecB (local)               : a vector associated with sectiondm's local section
2257f84dd6b4Sksagiyam $  vecB (global)              : a vector associated with sectiondm's global section
2258f84dd6b4Sksagiyam $
2259f84dd6b4Sksagiyam $                                     rank 0    rank 1
2260f84dd6b4Sksagiyam $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2261f84dd6b4Sksagiyam $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2262f84dd6b4Sksagiyam $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2263f84dd6b4Sksagiyam $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2264f84dd6b4Sksagiyam $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2265f84dd6b4Sksagiyam $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2266f84dd6b4Sksagiyam $  sectionB->atlasDof             :     1 0 1 | 1 3
2267f84dd6b4Sksagiyam $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2268f84dd6b4Sksagiyam $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2269f84dd6b4Sksagiyam $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2270f84dd6b4Sksagiyam $
2271f84dd6b4Sksagiyam $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2272f84dd6b4Sksagiyam 
2273db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`
2274f84dd6b4Sksagiyam @*/
2275f84dd6b4Sksagiyam PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2276f84dd6b4Sksagiyam {
2277f84dd6b4Sksagiyam   PetscBool      ishdf5;
2278f84dd6b4Sksagiyam 
2279f84dd6b4Sksagiyam   PetscFunctionBegin;
2280f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2281f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2282f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2283f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2284f84dd6b4Sksagiyam   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2285f84dd6b4Sksagiyam   if (localDofSF) PetscValidPointer(localDofSF, 6);
22869566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
22879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0));
2288f84dd6b4Sksagiyam   if (ishdf5) {
2289f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
22909566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2291f84dd6b4Sksagiyam #else
2292f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2293f84dd6b4Sksagiyam #endif
2294f84dd6b4Sksagiyam   }
22959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0));
2296f84dd6b4Sksagiyam   PetscFunctionReturn(0);
2297f84dd6b4Sksagiyam }
2298f84dd6b4Sksagiyam 
22998be3dfe1Sksagiyam /*@
23008be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
23018be3dfe1Sksagiyam 
23028be3dfe1Sksagiyam   Collective on DM
23038be3dfe1Sksagiyam 
23048be3dfe1Sksagiyam   Input Parameters:
23058be3dfe1Sksagiyam + dm        - The DM that represents the topology
23068be3dfe1Sksagiyam . viewer    - The PetscViewer that represents the on-disk vector data
23078be3dfe1Sksagiyam . sectiondm - The DM that contains the global section on which vec is defined
23088be3dfe1Sksagiyam . sf        - The SF that migrates the on-disk vector data into vec
23098be3dfe1Sksagiyam - vec       - The global vector to set values of
23108be3dfe1Sksagiyam 
23118be3dfe1Sksagiyam   Level: advanced
23128be3dfe1Sksagiyam 
23138be3dfe1Sksagiyam   Notes:
23148be3dfe1Sksagiyam   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.
23158be3dfe1Sksagiyam 
23168be3dfe1Sksagiyam   Typical calling sequence
23178be3dfe1Sksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
23188be3dfe1Sksagiyam $       DMSetType(dm, DMPLEX);
23198be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
23208be3dfe1Sksagiyam $       DMPlexTopologyLoad(dm, viewer, &sfX);
23218be3dfe1Sksagiyam $       DMClone(dm, &sectiondm);
23228be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
23238be3dfe1Sksagiyam $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
23248be3dfe1Sksagiyam $       DMGetGlobalVector(sectiondm, &vec);
23258be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
23268be3dfe1Sksagiyam $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
23278be3dfe1Sksagiyam $       DMRestoreGlobalVector(sectiondm, &vec);
23288be3dfe1Sksagiyam $       PetscSFDestroy(&gsf);
23298be3dfe1Sksagiyam $       PetscSFDestroy(&sfX);
23308be3dfe1Sksagiyam $       DMDestroy(&sectiondm);
23318be3dfe1Sksagiyam $       DMDestroy(&dm);
23328be3dfe1Sksagiyam 
2333db781477SPatrick Sanan .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`
23348be3dfe1Sksagiyam @*/
23358be3dfe1Sksagiyam PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
23368be3dfe1Sksagiyam {
23378be3dfe1Sksagiyam   PetscBool       ishdf5;
23388be3dfe1Sksagiyam 
23398be3dfe1Sksagiyam   PetscFunctionBegin;
23408be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23418be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23428be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
23438be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
23448be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
23458be3dfe1Sksagiyam   /* Check consistency */
23468be3dfe1Sksagiyam   {
23478be3dfe1Sksagiyam     PetscSection  section;
23488be3dfe1Sksagiyam     PetscBool     includesConstraints;
23498be3dfe1Sksagiyam     PetscInt      m, m1;
23508be3dfe1Sksagiyam 
23519566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
23529566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
23539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
23549566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
23559566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
235663a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
23578be3dfe1Sksagiyam   }
23589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
23599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0));
23608be3dfe1Sksagiyam   if (ishdf5) {
23618be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
23629566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
23638be3dfe1Sksagiyam #else
23648be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23658be3dfe1Sksagiyam #endif
23668be3dfe1Sksagiyam   }
23679566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0));
23688be3dfe1Sksagiyam   PetscFunctionReturn(0);
23698be3dfe1Sksagiyam }
23708be3dfe1Sksagiyam 
23718be3dfe1Sksagiyam /*@
23728be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
23738be3dfe1Sksagiyam 
23748be3dfe1Sksagiyam   Collective on DM
23758be3dfe1Sksagiyam 
23768be3dfe1Sksagiyam   Input Parameters:
23778be3dfe1Sksagiyam + dm        - The DM that represents the topology
23788be3dfe1Sksagiyam . viewer    - The PetscViewer that represents the on-disk vector data
23798be3dfe1Sksagiyam . sectiondm - The DM that contains the local section on which vec is defined
23808be3dfe1Sksagiyam . sf        - The SF that migrates the on-disk vector data into vec
23818be3dfe1Sksagiyam - vec       - The local vector to set values of
23828be3dfe1Sksagiyam 
23838be3dfe1Sksagiyam   Level: advanced
23848be3dfe1Sksagiyam 
23858be3dfe1Sksagiyam   Notes:
23868be3dfe1Sksagiyam   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.
23878be3dfe1Sksagiyam 
23888be3dfe1Sksagiyam   Typical calling sequence
23898be3dfe1Sksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
23908be3dfe1Sksagiyam $       DMSetType(dm, DMPLEX);
23918be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
23928be3dfe1Sksagiyam $       DMPlexTopologyLoad(dm, viewer, &sfX);
23938be3dfe1Sksagiyam $       DMClone(dm, &sectiondm);
23948be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
23958be3dfe1Sksagiyam $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
23968be3dfe1Sksagiyam $       DMGetLocalVector(sectiondm, &vec);
23978be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
23988be3dfe1Sksagiyam $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
23998be3dfe1Sksagiyam $       DMRestoreLocalVector(sectiondm, &vec);
24008be3dfe1Sksagiyam $       PetscSFDestroy(&lsf);
24018be3dfe1Sksagiyam $       PetscSFDestroy(&sfX);
24028be3dfe1Sksagiyam $       DMDestroy(&sectiondm);
24038be3dfe1Sksagiyam $       DMDestroy(&dm);
24048be3dfe1Sksagiyam 
2405db781477SPatrick Sanan .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`
24068be3dfe1Sksagiyam @*/
24078be3dfe1Sksagiyam PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
24088be3dfe1Sksagiyam {
24098be3dfe1Sksagiyam   PetscBool       ishdf5;
24108be3dfe1Sksagiyam 
24118be3dfe1Sksagiyam   PetscFunctionBegin;
24128be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24138be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24148be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24158be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
24168be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
24178be3dfe1Sksagiyam   /* Check consistency */
24188be3dfe1Sksagiyam   {
24198be3dfe1Sksagiyam     PetscSection  section;
24208be3dfe1Sksagiyam     PetscBool     includesConstraints;
24218be3dfe1Sksagiyam     PetscInt      m, m1;
24228be3dfe1Sksagiyam 
24239566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24249566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
24259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24269566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24279566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
242863a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
24298be3dfe1Sksagiyam   }
24309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
24319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0));
24328be3dfe1Sksagiyam   if (ishdf5) {
24338be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
24349566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
24358be3dfe1Sksagiyam #else
24368be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24378be3dfe1Sksagiyam #endif
24388be3dfe1Sksagiyam   }
24399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0));
24408be3dfe1Sksagiyam   PetscFunctionReturn(0);
24418be3dfe1Sksagiyam }
24428be3dfe1Sksagiyam 
2443552f7358SJed Brown PetscErrorCode DMDestroy_Plex(DM dm)
2444552f7358SJed Brown {
2445552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2446552f7358SJed Brown 
2447552f7358SJed Brown   PetscFunctionBegin;
24489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL));
24499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL));
24509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL));
24519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL));
24522e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL));
24532e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL));
24542e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL));
24552e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL));
24562e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL));
24576bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL));
24586bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL));
2459c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL));
2460c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL));
24610d644c17SKarl Rupp   if (--mesh->refct > 0) PetscFunctionReturn(0);
24629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
24639566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
24649566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
24659566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
24669566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
24679566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
24689566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->facesTmp));
24699566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
24709566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
24719566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
24729566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
24739566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
24749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
24759566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
24769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
24779566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
24789566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
24799566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
24809566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
24819566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
24829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
24839566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
24849566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
24859566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
24869566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
24879566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2488552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
24899566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
2490552f7358SJed Brown   PetscFunctionReturn(0);
2491552f7358SJed Brown }
2492552f7358SJed Brown 
2493b412c318SBarry Smith PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2494552f7358SJed Brown {
24958d1174e4SMatthew G. Knepley   PetscSection           sectionGlobal;
2496acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
24979fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2498837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2499b412c318SBarry Smith   MatType                mtype;
25001428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2501552f7358SJed Brown 
2502552f7358SJed Brown   PetscFunctionBegin;
25039566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2504b412c318SBarry Smith   mtype = dm->mattype;
25059566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
25069566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
25079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
25089fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm)));
25099566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
25109566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
25119566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
25129566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
25139566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2514acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
25159566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
25169566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
25179566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
25189566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
25199566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
25209566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
25219566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
25229566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2523552f7358SJed Brown   if (!isShell) {
2524837628f4SStefano Zampini     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
25259fca9976SJed Brown     PetscInt  *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2526fad22124SMatthew G Knepley     PetscInt  pStart, pEnd, p, dof, cdof;
2527552f7358SJed Brown 
25289566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm,&ltog));
25299fca9976SJed Brown 
25309fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
25319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2532e432b41dSStefano Zampini     for (p = pStart; p < pEnd; ++p) {
25339fca9976SJed Brown       PetscInt bdof, offset;
2534a9d99c84SMatthew G. Knepley 
25359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
25369fca9976SJed Brown       PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
25379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
25389fca9976SJed Brown       for (PetscInt i=0; i < dof - cdof; i++)
25399fca9976SJed Brown         pblocks[offset - localStart + i] = dof - cdof;
25401d17a0a3SMatthew G. Knepley       dof  = dof < 0 ? -(dof+1) : dof;
25411d17a0a3SMatthew G. Knepley       bdof = cdof && (dof-cdof) ? 1 : dof;
25421d17a0a3SMatthew G. Knepley       if (dof) {
25431d17a0a3SMatthew G. Knepley         if (bs < 0)          {bs = bdof;}
25449fca9976SJed Brown         else if (bs != bdof) {bs = 1;}
2545552f7358SJed Brown       }
25462a28c762SMatthew G Knepley     }
25472a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2548e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2549e432b41dSStefano Zampini     bsLocal[1] = bs;
25509566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax));
2551e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2552e432b41dSStefano Zampini     else bs = bsMinMax[0];
25536fd5c86aSStefano Zampini     bs = PetscMax(1,bs);
25549566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog));
25550682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
25569566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
25579566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
25580682b8bbSJed Brown     } else {
25599566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu));
25609566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
25619566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2562552f7358SJed Brown     }
25639fca9976SJed Brown     { // Consolidate blocks
25649fca9976SJed Brown       PetscInt nblocks = 0;
25659fca9976SJed Brown       for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) {
25669fca9976SJed Brown         if (pblocks[i] == 0) continue;
25679fca9976SJed Brown         pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
25689fca9976SJed Brown         for (PetscInt j=1; j<pblocks[i]; j++) {
25699fca9976SJed Brown            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]);
25709fca9976SJed Brown         }
25719fca9976SJed Brown       }
25729fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
25739fca9976SJed Brown     }
25749fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2575aa0f6e3cSJed Brown   }
25769566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
2577552f7358SJed Brown   PetscFunctionReturn(0);
2578552f7358SJed Brown }
2579552f7358SJed Brown 
25807cd05799SMatthew G. Knepley /*@
2581a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2582be36d101SStefano Zampini 
2583be36d101SStefano Zampini   Not collective
2584be36d101SStefano Zampini 
2585be36d101SStefano Zampini   Input Parameter:
2586be36d101SStefano Zampini . mesh - The DMPlex
2587be36d101SStefano Zampini 
2588be36d101SStefano Zampini   Output Parameters:
2589be36d101SStefano Zampini . subsection - The subdomain section
2590be36d101SStefano Zampini 
2591be36d101SStefano Zampini   Level: developer
2592be36d101SStefano Zampini 
2593be36d101SStefano Zampini .seealso:
25947cd05799SMatthew G. Knepley @*/
2595be36d101SStefano Zampini PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2596be36d101SStefano Zampini {
2597be36d101SStefano Zampini   DM_Plex       *mesh = (DM_Plex*) dm->data;
2598be36d101SStefano Zampini 
2599be36d101SStefano Zampini   PetscFunctionBegin;
2600be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2601be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2602be36d101SStefano Zampini     PetscSection section;
2603be36d101SStefano Zampini     PetscSF      sf;
2604be36d101SStefano Zampini 
26059566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf));
26069566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm,&section));
26079566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection));
26089566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2609be36d101SStefano Zampini   }
2610be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
2611be36d101SStefano Zampini   PetscFunctionReturn(0);
2612be36d101SStefano Zampini }
2613be36d101SStefano Zampini 
2614552f7358SJed Brown /*@
2615552f7358SJed Brown   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2616552f7358SJed Brown 
2617552f7358SJed Brown   Not collective
2618552f7358SJed Brown 
2619552f7358SJed Brown   Input Parameter:
2620552f7358SJed Brown . mesh - The DMPlex
2621552f7358SJed Brown 
2622552f7358SJed Brown   Output Parameters:
2623552f7358SJed Brown + pStart - The first mesh point
2624552f7358SJed Brown - pEnd   - The upper bound for mesh points
2625552f7358SJed Brown 
2626552f7358SJed Brown   Level: beginner
2627552f7358SJed Brown 
2628db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetChart()`
2629552f7358SJed Brown @*/
2630552f7358SJed Brown PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2631552f7358SJed Brown {
2632552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2633552f7358SJed Brown 
2634552f7358SJed Brown   PetscFunctionBegin;
2635552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2637552f7358SJed Brown   PetscFunctionReturn(0);
2638552f7358SJed Brown }
2639552f7358SJed Brown 
2640552f7358SJed Brown /*@
2641552f7358SJed Brown   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2642552f7358SJed Brown 
2643552f7358SJed Brown   Not collective
2644552f7358SJed Brown 
2645552f7358SJed Brown   Input Parameters:
2646552f7358SJed Brown + mesh - The DMPlex
2647552f7358SJed Brown . pStart - The first mesh point
2648552f7358SJed Brown - pEnd   - The upper bound for mesh points
2649552f7358SJed Brown 
2650552f7358SJed Brown   Output Parameters:
2651552f7358SJed Brown 
2652552f7358SJed Brown   Level: beginner
2653552f7358SJed Brown 
2654db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetChart()`
2655552f7358SJed Brown @*/
2656552f7358SJed Brown PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2657552f7358SJed Brown {
2658552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2659552f7358SJed Brown 
2660552f7358SJed Brown   PetscFunctionBegin;
2661552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26629566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
26639566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2664552f7358SJed Brown   PetscFunctionReturn(0);
2665552f7358SJed Brown }
2666552f7358SJed Brown 
2667552f7358SJed Brown /*@
2668eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2669552f7358SJed Brown 
2670552f7358SJed Brown   Not collective
2671552f7358SJed Brown 
2672552f7358SJed Brown   Input Parameters:
2673552f7358SJed Brown + mesh - The DMPlex
2674eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
2675552f7358SJed Brown 
2676552f7358SJed Brown   Output Parameter:
2677552f7358SJed Brown . size - The cone size for point p
2678552f7358SJed Brown 
2679552f7358SJed Brown   Level: beginner
2680552f7358SJed Brown 
2681db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2682552f7358SJed Brown @*/
2683552f7358SJed Brown PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2684552f7358SJed Brown {
2685552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2686552f7358SJed Brown 
2687552f7358SJed Brown   PetscFunctionBegin;
2688552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2689dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
26909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
2691552f7358SJed Brown   PetscFunctionReturn(0);
2692552f7358SJed Brown }
2693552f7358SJed Brown 
2694552f7358SJed Brown /*@
2695eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2696552f7358SJed Brown 
2697552f7358SJed Brown   Not collective
2698552f7358SJed Brown 
2699552f7358SJed Brown   Input Parameters:
2700552f7358SJed Brown + mesh - The DMPlex
2701eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2702552f7358SJed Brown - size - The cone size for point p
2703552f7358SJed Brown 
2704552f7358SJed Brown   Output Parameter:
2705552f7358SJed Brown 
2706552f7358SJed Brown   Note:
2707552f7358SJed Brown   This should be called after DMPlexSetChart().
2708552f7358SJed Brown 
2709552f7358SJed Brown   Level: beginner
2710552f7358SJed Brown 
2711db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2712552f7358SJed Brown @*/
2713552f7358SJed Brown PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2714552f7358SJed Brown {
2715552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2716552f7358SJed Brown 
2717552f7358SJed Brown   PetscFunctionBegin;
2718552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27199566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
2720552f7358SJed Brown   PetscFunctionReturn(0);
2721552f7358SJed Brown }
2722552f7358SJed Brown 
2723f5a469b9SMatthew G. Knepley /*@
2724eaf898f9SPatrick Sanan   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2725f5a469b9SMatthew G. Knepley 
2726f5a469b9SMatthew G. Knepley   Not collective
2727f5a469b9SMatthew G. Knepley 
2728f5a469b9SMatthew G. Knepley   Input Parameters:
2729f5a469b9SMatthew G. Knepley + mesh - The DMPlex
2730eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2731f5a469b9SMatthew G. Knepley - size - The additional cone size for point p
2732f5a469b9SMatthew G. Knepley 
2733f5a469b9SMatthew G. Knepley   Output Parameter:
2734f5a469b9SMatthew G. Knepley 
2735f5a469b9SMatthew G. Knepley   Note:
2736f5a469b9SMatthew G. Knepley   This should be called after DMPlexSetChart().
2737f5a469b9SMatthew G. Knepley 
2738f5a469b9SMatthew G. Knepley   Level: beginner
2739f5a469b9SMatthew G. Knepley 
2740db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2741f5a469b9SMatthew G. Knepley @*/
2742f5a469b9SMatthew G. Knepley PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2743f5a469b9SMatthew G. Knepley {
2744f5a469b9SMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
2745f5a469b9SMatthew G. Knepley   PetscFunctionBegin;
2746f5a469b9SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27479566063dSJacob Faibussowitsch   PetscCall(PetscSectionAddDof(mesh->coneSection, p, size));
2748f5a469b9SMatthew G. Knepley   PetscFunctionReturn(0);
2749f5a469b9SMatthew G. Knepley }
2750f5a469b9SMatthew G. Knepley 
2751552f7358SJed Brown /*@C
2752eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2753552f7358SJed Brown 
2754552f7358SJed Brown   Not collective
2755552f7358SJed Brown 
2756552f7358SJed Brown   Input Parameters:
2757833c876bSVaclav Hapla + dm - The DMPlex
2758eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
2759552f7358SJed Brown 
2760552f7358SJed Brown   Output Parameter:
2761552f7358SJed Brown . cone - An array of points which are on the in-edges for point p
2762552f7358SJed Brown 
2763552f7358SJed Brown   Level: beginner
2764552f7358SJed Brown 
27653813dfbdSMatthew G Knepley   Fortran Notes:
27663813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
27673813dfbdSMatthew G Knepley   include petsc.h90 in your code.
2768922102d1SVaclav Hapla   You must also call DMPlexRestoreCone() after you finish using the returned array.
2769922102d1SVaclav Hapla   DMPlexRestoreCone() is not needed/available in C.
27703813dfbdSMatthew G Knepley 
2771db781477SPatrick Sanan .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`
2772552f7358SJed Brown @*/
2773552f7358SJed Brown PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2774552f7358SJed Brown {
2775552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2776552f7358SJed Brown   PetscInt       off;
2777552f7358SJed Brown 
2778552f7358SJed Brown   PetscFunctionBegin;
2779552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2780552f7358SJed Brown   PetscValidPointer(cone, 3);
27819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
2782552f7358SJed Brown   *cone = &mesh->cones[off];
2783552f7358SJed Brown   PetscFunctionReturn(0);
2784552f7358SJed Brown }
2785552f7358SJed Brown 
27860ce7577fSVaclav Hapla /*@C
27870ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
27880ce7577fSVaclav Hapla 
27890ce7577fSVaclav Hapla   Not collective
27900ce7577fSVaclav Hapla 
27910ce7577fSVaclav Hapla   Input Parameters:
27920ce7577fSVaclav Hapla + dm - The DMPlex
27930ce7577fSVaclav Hapla - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
27940ce7577fSVaclav Hapla 
2795d8d19677SJose E. Roman   Output Parameters:
27960ce7577fSVaclav Hapla + pConesSection - PetscSection describing the layout of pCones
27970ce7577fSVaclav Hapla - pCones - An array of points which are on the in-edges for the point set p
27980ce7577fSVaclav Hapla 
27990ce7577fSVaclav Hapla   Level: intermediate
28000ce7577fSVaclav Hapla 
2801db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`
28020ce7577fSVaclav Hapla @*/
28030ce7577fSVaclav Hapla PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
28040ce7577fSVaclav Hapla {
28050ce7577fSVaclav Hapla   PetscSection        cs, newcs;
28060ce7577fSVaclav Hapla   PetscInt            *cones;
28070ce7577fSVaclav Hapla   PetscInt            *newarr=NULL;
28080ce7577fSVaclav Hapla   PetscInt            n;
28090ce7577fSVaclav Hapla 
28100ce7577fSVaclav Hapla   PetscFunctionBegin;
28119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
28129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
28139566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL));
28140ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
28150ce7577fSVaclav Hapla   if (pCones) {
28169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
28179566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
28180ce7577fSVaclav Hapla   }
28190ce7577fSVaclav Hapla   PetscFunctionReturn(0);
28200ce7577fSVaclav Hapla }
28210ce7577fSVaclav Hapla 
2822af9eab45SVaclav Hapla /*@
2823af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2824d4636a37SVaclav Hapla 
2825d4636a37SVaclav Hapla   Not collective
2826d4636a37SVaclav Hapla 
2827d4636a37SVaclav Hapla   Input Parameters:
2828d4636a37SVaclav Hapla + dm - The DMPlex
2829af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2830d4636a37SVaclav Hapla 
2831d4636a37SVaclav Hapla   Output Parameter:
2832af9eab45SVaclav Hapla . expandedPoints - An array of vertices recursively expanded from input points
2833d4636a37SVaclav Hapla 
2834d4636a37SVaclav Hapla   Level: advanced
2835d4636a37SVaclav Hapla 
2836af9eab45SVaclav Hapla   Notes:
2837af9eab45SVaclav Hapla   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2838af9eab45SVaclav Hapla   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2839af9eab45SVaclav Hapla 
2840db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()`
2841d4636a37SVaclav Hapla @*/
2842af9eab45SVaclav Hapla PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2843d4636a37SVaclav Hapla {
2844af9eab45SVaclav Hapla   IS                  *expandedPointsAll;
2845af9eab45SVaclav Hapla   PetscInt            depth;
2846d4636a37SVaclav Hapla 
2847d4636a37SVaclav Hapla   PetscFunctionBegin;
2848af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2849af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2850af9eab45SVaclav Hapla   PetscValidPointer(expandedPoints, 3);
28519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2852af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
28539566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
28549566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2855af9eab45SVaclav Hapla   PetscFunctionReturn(0);
2856af9eab45SVaclav Hapla }
2857af9eab45SVaclav Hapla 
2858af9eab45SVaclav Hapla /*@
2859af9eab45SVaclav 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).
2860af9eab45SVaclav Hapla 
2861af9eab45SVaclav Hapla   Not collective
2862af9eab45SVaclav Hapla 
2863af9eab45SVaclav Hapla   Input Parameters:
2864af9eab45SVaclav Hapla + dm - The DMPlex
2865af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2866af9eab45SVaclav Hapla 
2867d8d19677SJose E. Roman   Output Parameters:
2868af9eab45SVaclav Hapla + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2869af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
2870af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
2871af9eab45SVaclav Hapla 
2872af9eab45SVaclav Hapla   Level: advanced
2873af9eab45SVaclav Hapla 
2874af9eab45SVaclav Hapla   Notes:
2875af9eab45SVaclav Hapla   Like DMPlexGetConeTuple() but recursive.
2876af9eab45SVaclav Hapla 
2877af9eab45SVaclav 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.
2878af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2879af9eab45SVaclav Hapla 
2880af9eab45SVaclav 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:
2881af9eab45SVaclav Hapla   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2882af9eab45SVaclav Hapla   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2883af9eab45SVaclav Hapla 
2884db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()`
2885af9eab45SVaclav Hapla @*/
2886af9eab45SVaclav Hapla PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2887af9eab45SVaclav Hapla {
2888af9eab45SVaclav Hapla   const PetscInt      *arr0=NULL, *cone=NULL;
2889af9eab45SVaclav Hapla   PetscInt            *arr=NULL, *newarr=NULL;
2890af9eab45SVaclav Hapla   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2891af9eab45SVaclav Hapla   IS                  *expandedPoints_;
2892af9eab45SVaclav Hapla   PetscSection        *sections_;
2893af9eab45SVaclav Hapla 
2894af9eab45SVaclav Hapla   PetscFunctionBegin;
2895af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2896af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2897af9eab45SVaclav Hapla   if (depth) PetscValidIntPointer(depth, 3);
2898af9eab45SVaclav Hapla   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2899af9eab45SVaclav Hapla   if (sections) PetscValidPointer(sections, 5);
29009566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
29019566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
29029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
29039566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
29049566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
2905af9eab45SVaclav Hapla   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2906af9eab45SVaclav Hapla   for (d=depth_-1; d>=0; d--) {
29079566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
29089566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
2909af9eab45SVaclav Hapla     for (i=0; i<n; i++) {
29109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end));
2911af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
29129566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
29139566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
2914af9eab45SVaclav Hapla       } else {
29159566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
2916af9eab45SVaclav Hapla       }
2917af9eab45SVaclav Hapla     }
29189566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
29199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
29209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
2921af9eab45SVaclav Hapla     for (i=0; i<n; i++) {
29229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
29239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
2924af9eab45SVaclav Hapla       if (cn > 1) {
29259566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
29269566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt)));
2927af9eab45SVaclav Hapla       } else {
2928af9eab45SVaclav Hapla         newarr[co] = arr[i];
2929af9eab45SVaclav Hapla       }
2930af9eab45SVaclav Hapla     }
29319566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
2932af9eab45SVaclav Hapla     arr = newarr;
2933af9eab45SVaclav Hapla     n = newn;
2934af9eab45SVaclav Hapla   }
29359566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
2936af9eab45SVaclav Hapla   *depth = depth_;
2937af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
2938af9eab45SVaclav Hapla   else {
29399566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
29409566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
2941af9eab45SVaclav Hapla   }
2942af9eab45SVaclav Hapla   if (sections) *sections = sections_;
2943af9eab45SVaclav Hapla   else {
29449566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
29459566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
2946af9eab45SVaclav Hapla   }
2947af9eab45SVaclav Hapla   PetscFunctionReturn(0);
2948af9eab45SVaclav Hapla }
2949af9eab45SVaclav Hapla 
2950af9eab45SVaclav Hapla /*@
2951af9eab45SVaclav Hapla   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2952af9eab45SVaclav Hapla 
2953af9eab45SVaclav Hapla   Not collective
2954af9eab45SVaclav Hapla 
2955af9eab45SVaclav Hapla   Input Parameters:
2956af9eab45SVaclav Hapla + dm - The DMPlex
2957af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2958af9eab45SVaclav Hapla 
2959d8d19677SJose E. Roman   Output Parameters:
2960af9eab45SVaclav Hapla + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2961af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
2962af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
2963af9eab45SVaclav Hapla 
2964af9eab45SVaclav Hapla   Level: advanced
2965af9eab45SVaclav Hapla 
2966af9eab45SVaclav Hapla   Notes:
2967af9eab45SVaclav Hapla   See DMPlexGetConeRecursive() for details.
2968af9eab45SVaclav Hapla 
2969db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()`
2970af9eab45SVaclav Hapla @*/
2971af9eab45SVaclav Hapla PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2972af9eab45SVaclav Hapla {
2973af9eab45SVaclav Hapla   PetscInt            d, depth_;
2974af9eab45SVaclav Hapla 
2975af9eab45SVaclav Hapla   PetscFunctionBegin;
29769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
29771dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2978af9eab45SVaclav Hapla   if (depth) *depth = 0;
2979af9eab45SVaclav Hapla   if (expandedPoints) {
29809566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
29819566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
2982af9eab45SVaclav Hapla   }
2983af9eab45SVaclav Hapla   if (sections)  {
29849566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
29859566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
2986af9eab45SVaclav Hapla   }
2987d4636a37SVaclav Hapla   PetscFunctionReturn(0);
2988d4636a37SVaclav Hapla }
2989d4636a37SVaclav Hapla 
2990552f7358SJed Brown /*@
299192371b87SBarry 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
2992552f7358SJed Brown 
2993552f7358SJed Brown   Not collective
2994552f7358SJed Brown 
2995552f7358SJed Brown   Input Parameters:
2996552f7358SJed Brown + mesh - The DMPlex
2997eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2998552f7358SJed Brown - cone - An array of points which are on the in-edges for point p
2999552f7358SJed Brown 
3000552f7358SJed Brown   Output Parameter:
3001552f7358SJed Brown 
3002552f7358SJed Brown   Note:
3003552f7358SJed Brown   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
3004552f7358SJed Brown 
3005552f7358SJed Brown   Level: beginner
3006552f7358SJed Brown 
3007db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3008552f7358SJed Brown @*/
3009552f7358SJed Brown PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3010552f7358SJed Brown {
3011552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3012552f7358SJed Brown   PetscInt       pStart, pEnd;
3013552f7358SJed Brown   PetscInt       dof, off, c;
3014552f7358SJed Brown 
3015552f7358SJed Brown   PetscFunctionBegin;
3016552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
30189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3019dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(cone, 3);
30209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
302163a3b9bcSJacob 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);
3022552f7358SJed Brown   for (c = 0; c < dof; ++c) {
302363a3b9bcSJacob 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);
3024552f7358SJed Brown     mesh->cones[off+c] = cone[c];
3025552f7358SJed Brown   }
3026552f7358SJed Brown   PetscFunctionReturn(0);
3027552f7358SJed Brown }
3028552f7358SJed Brown 
3029552f7358SJed Brown /*@C
3030eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3031552f7358SJed Brown 
3032552f7358SJed Brown   Not collective
3033552f7358SJed Brown 
3034552f7358SJed Brown   Input Parameters:
3035552f7358SJed Brown + mesh - The DMPlex
3036eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3037552f7358SJed Brown 
3038552f7358SJed Brown   Output Parameter:
3039552f7358SJed Brown . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
3040b5a892a1SMatthew G. Knepley                     integer giving the prescription for cone traversal.
3041552f7358SJed Brown 
3042552f7358SJed Brown   Level: beginner
3043552f7358SJed Brown 
3044b5a892a1SMatthew G. Knepley   Notes:
3045b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3046b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3047b5a892a1SMatthew G. Knepley   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
3048b5a892a1SMatthew G. Knepley   with the identity.
3049b5a892a1SMatthew G. Knepley 
30503813dfbdSMatthew G Knepley   Fortran Notes:
30513813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
30523813dfbdSMatthew G Knepley   include petsc.h90 in your code.
30533b12b3d8SVaclav Hapla   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
3054922102d1SVaclav Hapla   DMPlexRestoreConeOrientation() is not needed/available in C.
30553813dfbdSMatthew G Knepley 
3056db781477SPatrick Sanan .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3057552f7358SJed Brown @*/
3058552f7358SJed Brown PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3059552f7358SJed Brown {
3060552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3061552f7358SJed Brown   PetscInt       off;
3062552f7358SJed Brown 
3063552f7358SJed Brown   PetscFunctionBegin;
3064552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
306576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3066552f7358SJed Brown     PetscInt dof;
30679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3068552f7358SJed Brown     if (dof) PetscValidPointer(coneOrientation, 3);
3069552f7358SJed Brown   }
30709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
30710d644c17SKarl Rupp 
3072552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
3073552f7358SJed Brown   PetscFunctionReturn(0);
3074552f7358SJed Brown }
3075552f7358SJed Brown 
3076552f7358SJed Brown /*@
3077eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3078552f7358SJed Brown 
3079552f7358SJed Brown   Not collective
3080552f7358SJed Brown 
3081552f7358SJed Brown   Input Parameters:
3082552f7358SJed Brown + mesh - The DMPlex
3083eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3084b5a892a1SMatthew G. Knepley - coneOrientation - An array of orientations
3085552f7358SJed Brown   Output Parameter:
3086552f7358SJed Brown 
3087b5a892a1SMatthew G. Knepley   Notes:
3088552f7358SJed Brown   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
3089552f7358SJed Brown 
3090b5a892a1SMatthew G. Knepley   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
3091b5a892a1SMatthew G. Knepley 
3092552f7358SJed Brown   Level: beginner
3093552f7358SJed Brown 
3094db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3095552f7358SJed Brown @*/
3096552f7358SJed Brown PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3097552f7358SJed Brown {
3098552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3099552f7358SJed Brown   PetscInt       pStart, pEnd;
3100552f7358SJed Brown   PetscInt       dof, off, c;
3101552f7358SJed Brown 
3102552f7358SJed Brown   PetscFunctionBegin;
3103552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
31059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3106dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(coneOrientation, 3);
31079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
310863a3b9bcSJacob 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);
3109552f7358SJed Brown   for (c = 0; c < dof; ++c) {
3110552f7358SJed Brown     PetscInt cdof, o = coneOrientation[c];
3111552f7358SJed Brown 
31129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof));
31131dca8a05SBarry 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);
3114552f7358SJed Brown     mesh->coneOrientations[off+c] = o;
3115552f7358SJed Brown   }
3116552f7358SJed Brown   PetscFunctionReturn(0);
3117552f7358SJed Brown }
3118552f7358SJed Brown 
31197cd05799SMatthew G. Knepley /*@
3120eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
31217cd05799SMatthew G. Knepley 
31227cd05799SMatthew G. Knepley   Not collective
31237cd05799SMatthew G. Knepley 
31247cd05799SMatthew G. Knepley   Input Parameters:
31257cd05799SMatthew G. Knepley + mesh - The DMPlex
3126eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
31277cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
31287cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
31297cd05799SMatthew G. Knepley 
31307cd05799SMatthew G. Knepley   Level: beginner
31317cd05799SMatthew G. Knepley 
3132db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
31337cd05799SMatthew G. Knepley @*/
3134552f7358SJed Brown PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3135552f7358SJed Brown {
3136552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3137552f7358SJed Brown   PetscInt       pStart, pEnd;
3138552f7358SJed Brown   PetscInt       dof, off;
3139552f7358SJed Brown 
3140552f7358SJed Brown   PetscFunctionBegin;
3141552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
314363a3b9bcSJacob 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);
314463a3b9bcSJacob 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);
31459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
31469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
314763a3b9bcSJacob 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);
3148552f7358SJed Brown   mesh->cones[off+conePos] = conePoint;
3149552f7358SJed Brown   PetscFunctionReturn(0);
3150552f7358SJed Brown }
3151552f7358SJed Brown 
31527cd05799SMatthew G. Knepley /*@
3153eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
31547cd05799SMatthew G. Knepley 
31557cd05799SMatthew G. Knepley   Not collective
31567cd05799SMatthew G. Knepley 
31577cd05799SMatthew G. Knepley   Input Parameters:
31587cd05799SMatthew G. Knepley + mesh - The DMPlex
3159eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
31607cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
31617cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
31627cd05799SMatthew G. Knepley 
31637cd05799SMatthew G. Knepley   Level: beginner
31647cd05799SMatthew G. Knepley 
3165b5a892a1SMatthew G. Knepley   Notes:
3166b5a892a1SMatthew G. Knepley   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3167b5a892a1SMatthew G. Knepley 
3168db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
31697cd05799SMatthew G. Knepley @*/
317077c88f5bSMatthew G Knepley PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
317177c88f5bSMatthew G Knepley {
317277c88f5bSMatthew G Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
317377c88f5bSMatthew G Knepley   PetscInt       pStart, pEnd;
317477c88f5bSMatthew G Knepley   PetscInt       dof, off;
317577c88f5bSMatthew G Knepley 
317677c88f5bSMatthew G Knepley   PetscFunctionBegin;
317777c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
317963a3b9bcSJacob 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);
31809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
31819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
318263a3b9bcSJacob 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);
318377c88f5bSMatthew G Knepley   mesh->coneOrientations[off+conePos] = coneOrientation;
318477c88f5bSMatthew G Knepley   PetscFunctionReturn(0);
318577c88f5bSMatthew G Knepley }
318677c88f5bSMatthew G Knepley 
3187552f7358SJed Brown /*@
3188eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3189552f7358SJed Brown 
3190552f7358SJed Brown   Not collective
3191552f7358SJed Brown 
3192552f7358SJed Brown   Input Parameters:
3193552f7358SJed Brown + mesh - The DMPlex
3194eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3195552f7358SJed Brown 
3196552f7358SJed Brown   Output Parameter:
3197552f7358SJed Brown . size - The support size for point p
3198552f7358SJed Brown 
3199552f7358SJed Brown   Level: beginner
3200552f7358SJed Brown 
3201db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3202552f7358SJed Brown @*/
3203552f7358SJed Brown PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3204552f7358SJed Brown {
3205552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3206552f7358SJed Brown 
3207552f7358SJed Brown   PetscFunctionBegin;
3208552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3209dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
32109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3211552f7358SJed Brown   PetscFunctionReturn(0);
3212552f7358SJed Brown }
3213552f7358SJed Brown 
3214552f7358SJed Brown /*@
3215eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3216552f7358SJed Brown 
3217552f7358SJed Brown   Not collective
3218552f7358SJed Brown 
3219552f7358SJed Brown   Input Parameters:
3220552f7358SJed Brown + mesh - The DMPlex
3221eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3222552f7358SJed Brown - size - The support size for point p
3223552f7358SJed Brown 
3224552f7358SJed Brown   Output Parameter:
3225552f7358SJed Brown 
3226552f7358SJed Brown   Note:
3227552f7358SJed Brown   This should be called after DMPlexSetChart().
3228552f7358SJed Brown 
3229552f7358SJed Brown   Level: beginner
3230552f7358SJed Brown 
3231db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3232552f7358SJed Brown @*/
3233552f7358SJed Brown PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3234552f7358SJed Brown {
3235552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3236552f7358SJed Brown 
3237552f7358SJed Brown   PetscFunctionBegin;
3238552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32399566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3240552f7358SJed Brown   PetscFunctionReturn(0);
3241552f7358SJed Brown }
3242552f7358SJed Brown 
3243552f7358SJed Brown /*@C
3244eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3245552f7358SJed Brown 
3246552f7358SJed Brown   Not collective
3247552f7358SJed Brown 
3248552f7358SJed Brown   Input Parameters:
3249552f7358SJed Brown + mesh - The DMPlex
3250eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3251552f7358SJed Brown 
3252552f7358SJed Brown   Output Parameter:
3253552f7358SJed Brown . support - An array of points which are on the out-edges for point p
3254552f7358SJed Brown 
3255552f7358SJed Brown   Level: beginner
3256552f7358SJed Brown 
32573813dfbdSMatthew G Knepley   Fortran Notes:
32583813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
32593813dfbdSMatthew G Knepley   include petsc.h90 in your code.
32603b12b3d8SVaclav Hapla   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3261922102d1SVaclav Hapla   DMPlexRestoreSupport() is not needed/available in C.
32623813dfbdSMatthew G Knepley 
3263db781477SPatrick Sanan .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3264552f7358SJed Brown @*/
3265552f7358SJed Brown PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3266552f7358SJed Brown {
3267552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3268552f7358SJed Brown   PetscInt       off;
3269552f7358SJed Brown 
3270552f7358SJed Brown   PetscFunctionBegin;
3271552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3272552f7358SJed Brown   PetscValidPointer(support, 3);
32739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3274552f7358SJed Brown   *support = &mesh->supports[off];
3275552f7358SJed Brown   PetscFunctionReturn(0);
3276552f7358SJed Brown }
3277552f7358SJed Brown 
3278552f7358SJed Brown /*@
327992371b87SBarry 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
3280552f7358SJed Brown 
3281552f7358SJed Brown   Not collective
3282552f7358SJed Brown 
3283552f7358SJed Brown   Input Parameters:
3284552f7358SJed Brown + mesh - The DMPlex
3285eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
328692371b87SBarry Smith - support - An array of points which are on the out-edges for point p
3287552f7358SJed Brown 
3288552f7358SJed Brown   Output Parameter:
3289552f7358SJed Brown 
3290552f7358SJed Brown   Note:
3291552f7358SJed Brown   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3292552f7358SJed Brown 
3293552f7358SJed Brown   Level: beginner
3294552f7358SJed Brown 
3295db781477SPatrick Sanan .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3296552f7358SJed Brown @*/
3297552f7358SJed Brown PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3298552f7358SJed Brown {
3299552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3300552f7358SJed Brown   PetscInt       pStart, pEnd;
3301552f7358SJed Brown   PetscInt       dof, off, c;
3302552f7358SJed Brown 
3303552f7358SJed Brown   PetscFunctionBegin;
3304552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
33069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3307dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(support, 3);
33089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
330963a3b9bcSJacob 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);
3310552f7358SJed Brown   for (c = 0; c < dof; ++c) {
331163a3b9bcSJacob 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);
3312552f7358SJed Brown     mesh->supports[off+c] = support[c];
3313552f7358SJed Brown   }
3314552f7358SJed Brown   PetscFunctionReturn(0);
3315552f7358SJed Brown }
3316552f7358SJed Brown 
33177cd05799SMatthew G. Knepley /*@
3318eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
33197cd05799SMatthew G. Knepley 
33207cd05799SMatthew G. Knepley   Not collective
33217cd05799SMatthew G. Knepley 
33227cd05799SMatthew G. Knepley   Input Parameters:
33237cd05799SMatthew G. Knepley + mesh - The DMPlex
3324eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
33257cd05799SMatthew G. Knepley . supportPos - The local index in the cone where the point should be put
33267cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
33277cd05799SMatthew G. Knepley 
33287cd05799SMatthew G. Knepley   Level: beginner
33297cd05799SMatthew G. Knepley 
3330db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
33317cd05799SMatthew G. Knepley @*/
3332552f7358SJed Brown PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3333552f7358SJed Brown {
3334552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3335552f7358SJed Brown   PetscInt       pStart, pEnd;
3336552f7358SJed Brown   PetscInt       dof, off;
3337552f7358SJed Brown 
3338552f7358SJed Brown   PetscFunctionBegin;
3339552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
33419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
33429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
334363a3b9bcSJacob 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);
334463a3b9bcSJacob 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);
334563a3b9bcSJacob 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);
3346552f7358SJed Brown   mesh->supports[off+supportPos] = supportPoint;
3347552f7358SJed Brown   PetscFunctionReturn(0);
3348552f7358SJed Brown }
3349552f7358SJed Brown 
3350b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3351b5a892a1SMatthew G. Knepley PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3352b5a892a1SMatthew G. Knepley {
3353b5a892a1SMatthew G. Knepley   switch (ct) {
3354b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
3355b5a892a1SMatthew G. Knepley       if (o == -1) return -2;
3356b5a892a1SMatthew G. Knepley       break;
3357b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
3358b5a892a1SMatthew G. Knepley       if (o == -3) return -1;
3359b5a892a1SMatthew G. Knepley       if (o == -2) return -3;
3360b5a892a1SMatthew G. Knepley       if (o == -1) return -2;
3361b5a892a1SMatthew G. Knepley       break;
3362b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
3363b5a892a1SMatthew G. Knepley       if (o == -4) return -2;
3364b5a892a1SMatthew G. Knepley       if (o == -3) return -1;
3365b5a892a1SMatthew G. Knepley       if (o == -2) return -4;
3366b5a892a1SMatthew G. Knepley       if (o == -1) return -3;
3367b5a892a1SMatthew G. Knepley       break;
3368b5a892a1SMatthew G. Knepley     default: return o;
3369b5a892a1SMatthew G. Knepley   }
3370b5a892a1SMatthew G. Knepley   return o;
3371b5a892a1SMatthew G. Knepley }
3372b5a892a1SMatthew G. Knepley 
3373b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3374b5a892a1SMatthew G. Knepley PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3375b5a892a1SMatthew G. Knepley {
3376b5a892a1SMatthew G. Knepley   switch (ct) {
3377b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
3378b5a892a1SMatthew G. Knepley       if ((o == -2) || (o == 1)) return -1;
3379b5a892a1SMatthew G. Knepley       if (o == -1) return 0;
3380b5a892a1SMatthew G. Knepley       break;
3381b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
3382b5a892a1SMatthew G. Knepley       if (o == -3) return -2;
3383b5a892a1SMatthew G. Knepley       if (o == -2) return -1;
3384b5a892a1SMatthew G. Knepley       if (o == -1) return -3;
3385b5a892a1SMatthew G. Knepley       break;
3386b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
3387b5a892a1SMatthew G. Knepley       if (o == -4) return -2;
3388b5a892a1SMatthew G. Knepley       if (o == -3) return -1;
3389b5a892a1SMatthew G. Knepley       if (o == -2) return -4;
3390b5a892a1SMatthew G. Knepley       if (o == -1) return -3;
3391b5a892a1SMatthew G. Knepley       break;
3392b5a892a1SMatthew G. Knepley     default: return o;
3393b5a892a1SMatthew G. Knepley   }
3394b5a892a1SMatthew G. Knepley   return o;
3395b5a892a1SMatthew G. Knepley }
3396b5a892a1SMatthew G. Knepley 
3397b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3398b5a892a1SMatthew G. Knepley PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3399b5a892a1SMatthew G. Knepley {
3400b5a892a1SMatthew G. Knepley   PetscInt       pStart, pEnd, p;
3401b5a892a1SMatthew G. Knepley 
3402b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
34039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3404b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3405b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3406b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3407b5a892a1SMatthew G. Knepley 
34089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
34099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
34109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3411b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3412b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3413b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3414b5a892a1SMatthew G. Knepley 
34159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3416b5a892a1SMatthew G. Knepley       switch (ct) {
3417b5a892a1SMatthew G. Knepley         case DM_POLYTOPE_SEGMENT:
34189566063dSJacob Faibussowitsch           if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
34199566063dSJacob Faibussowitsch           if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3420b5a892a1SMatthew G. Knepley           break;
3421b5a892a1SMatthew G. Knepley         case DM_POLYTOPE_TRIANGLE:
34229566063dSJacob Faibussowitsch           if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
34239566063dSJacob Faibussowitsch           if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
34249566063dSJacob Faibussowitsch           if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3425b5a892a1SMatthew G. Knepley           break;
3426b5a892a1SMatthew G. Knepley         case DM_POLYTOPE_QUADRILATERAL:
34279566063dSJacob Faibussowitsch           if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
34289566063dSJacob Faibussowitsch           if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
34299566063dSJacob Faibussowitsch           if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
34309566063dSJacob Faibussowitsch           if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3431b5a892a1SMatthew G. Knepley           break;
3432b5a892a1SMatthew G. Knepley         default: break;
3433b5a892a1SMatthew G. Knepley       }
3434b5a892a1SMatthew G. Knepley     }
3435b5a892a1SMatthew G. Knepley   }
3436b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3437b5a892a1SMatthew G. Knepley }
3438b5a892a1SMatthew G. Knepley 
3439012bc364SMatthew G. Knepley static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3440b5a892a1SMatthew G. Knepley {
3441b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3442b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3443b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3444b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3445b5a892a1SMatthew G. Knepley 
3446b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3447b5a892a1SMatthew G. Knepley   if (ornt) {
34489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3449b5a892a1SMatthew G. Knepley     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3450b5a892a1SMatthew G. Knepley   }
3451b5a892a1SMatthew G. Knepley   if (*points) {
3452b5a892a1SMatthew G. Knepley     closure = *points;
3453b5a892a1SMatthew G. Knepley   } else {
3454b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
34559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
34569566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure));
3457b5a892a1SMatthew G. Knepley   }
3458b5a892a1SMatthew G. Knepley   if (useCone) {
34599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &tmpSize));
34609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &tmp));
34619566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO));
3462b5a892a1SMatthew G. Knepley   } else {
34639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize));
34649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &tmp));
3465b5a892a1SMatthew G. Knepley   }
3466b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3467b5a892a1SMatthew G. Knepley     closure[off++] = p;
3468b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3469b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3470b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3471b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3472b5a892a1SMatthew G. Knepley     }
3473b5a892a1SMatthew G. Knepley   } else {
34745f80ce2aSJacob Faibussowitsch     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3475b5a892a1SMatthew G. Knepley 
3476b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3477b5a892a1SMatthew G. Knepley     closure[off++] = p;
3478b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3479b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3480b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3481b5a892a1SMatthew G. Knepley 
34829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3483b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3484b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3485b5a892a1SMatthew G. Knepley     }
3486b5a892a1SMatthew G. Knepley   }
3487b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize+1;
3488b5a892a1SMatthew G. Knepley   if (points)    *points    = closure;
3489b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3490b5a892a1SMatthew G. Knepley }
3491b5a892a1SMatthew G. Knepley 
3492b5a892a1SMatthew G. Knepley /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3493b5a892a1SMatthew G. Knepley static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3494b5a892a1SMatthew G. Knepley {
3495b5a892a1SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3496b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3497b5a892a1SMatthew G. Knepley   PetscInt       *pts,  *closure = NULL;
3498b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3499b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3500b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3501b5a892a1SMatthew G. Knepley 
3502b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
35039566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
35049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
35059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
35069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &ornt));
35079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3508b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    dim+1)-1)/(maxConeSize-1))    : dim+1;
3509b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1;
3510b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
3511b5a892a1SMatthew G. Knepley   if (*points) {pts  = *points;}
35129566063dSJacob Faibussowitsch   else         PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts));
3513b5a892a1SMatthew G. Knepley   c    = 0;
3514b5a892a1SMatthew G. Knepley   pts[c++] = point;
3515b5a892a1SMatthew G. Knepley   pts[c++] = o;
35169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft));
35179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure));
3518b5a892a1SMatthew G. Knepley   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
35199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure));
3520b5a892a1SMatthew G. Knepley   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
35219566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3522b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
35239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft));
3524b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d*2+0]];
3525b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]);
3526b5a892a1SMatthew G. Knepley   }
3527b5a892a1SMatthew G. Knepley   if (dim >= 3) {
3528b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
3529b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d*2+0]];
3530b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
3531b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
3532b5a892a1SMatthew G. Knepley 
35339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3534b5a892a1SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]));
35359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize));
35369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, fpoint, &fcone));
35379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt));
3538b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
3539b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc*2+0]];
3540b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc*2+1];
3541b5a892a1SMatthew G. Knepley 
3542b5a892a1SMatthew G. Knepley         for (i = 0; i < c; i += 2) if (pts[i] == cp) break;
3543b5a892a1SMatthew G. Knepley         if (i == c) {
35449566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3545b5a892a1SMatthew G. Knepley           pts[c++] = cp;
3546b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]);
3547b5a892a1SMatthew G. Knepley         }
3548b5a892a1SMatthew G. Knepley       }
3549b5a892a1SMatthew G. Knepley     }
3550b5a892a1SMatthew G. Knepley   }
3551b5a892a1SMatthew G. Knepley   *numPoints = c/2;
3552b5a892a1SMatthew G. Knepley   *points    = pts;
3553b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3554b5a892a1SMatthew G. Knepley }
3555b5a892a1SMatthew G. Knepley 
3556b5a892a1SMatthew G. Knepley PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3557b5a892a1SMatthew G. Knepley {
3558b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
3559b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
3560b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3561b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3562b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
3563b5a892a1SMatthew G. Knepley 
3564b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
35659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
3566b5a892a1SMatthew G. Knepley   if (depth == 1) {
35679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3568b5a892a1SMatthew G. Knepley     PetscFunctionReturn(0);
3569b5a892a1SMatthew G. Knepley   }
35709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
3571b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3572b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
35739566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3574b5a892a1SMatthew G. Knepley     PetscFunctionReturn(0);
3575b5a892a1SMatthew G. Knepley   }
35769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3577b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    depth+1)-1)/(maxConeSize-1))    : depth+1;
3578b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1;
3579b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
35809566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo));
3581b5a892a1SMatthew G. Knepley   if (*points) {closure = *points;}
35829566063dSJacob Faibussowitsch   else         PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure));
3583b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
3584b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
3585b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
3586b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
3587b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
3588b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3589b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
3590b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
3591b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
3592b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType) fifo[fifoStart++];
3593b5a892a1SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3594b5a892a1SMatthew G. Knepley     const PetscInt      *tmp, *tmpO;
3595b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
3596b5a892a1SMatthew G. Knepley 
3597b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
3598b5a892a1SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2;
359963a3b9bcSJacob 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);
3600b5a892a1SMatthew G. Knepley     }
3601b5a892a1SMatthew G. Knepley     if (useCone) {
36029566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &tmpSize));
36039566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &tmp));
36049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO));
3605b5a892a1SMatthew G. Knepley     } else {
36069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize));
36079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, q, &tmp));
3608b5a892a1SMatthew G. Knepley       tmpO = NULL;
3609b5a892a1SMatthew G. Knepley     }
3610b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3611b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t*2]   : t;
3612b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0;
3613b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
36149566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
3615b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3616b5a892a1SMatthew G. Knepley       PetscInt       c;
3617b5a892a1SMatthew G. Knepley 
3618b5a892a1SMatthew G. Knepley       /* Check for duplicate */
3619b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
3620b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
3621b5a892a1SMatthew G. Knepley       }
3622b5a892a1SMatthew G. Knepley       if (c == closureSize) {
3623b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
3624b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
3625b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
3626b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
3627b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
3628b5a892a1SMatthew G. Knepley       }
3629b5a892a1SMatthew G. Knepley     }
3630b5a892a1SMatthew G. Knepley   }
36319566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo));
3632b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize/2;
3633b5a892a1SMatthew G. Knepley   if (points)    *points    = closure;
3634b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3635b5a892a1SMatthew G. Knepley }
3636b5a892a1SMatthew G. Knepley 
3637552f7358SJed Brown /*@C
3638eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3639552f7358SJed Brown 
3640552f7358SJed Brown   Not collective
3641552f7358SJed Brown 
3642552f7358SJed Brown   Input Parameters:
3643b5a892a1SMatthew G. Knepley + dm      - The DMPlex
3644b5a892a1SMatthew G. Knepley . p       - The mesh point
36456b867d5aSJose E. Roman - useCone - PETSC_TRUE for the closure, otherwise return the star
3646552f7358SJed Brown 
36476b867d5aSJose E. Roman   Input/Output Parameter:
36486b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
36496b867d5aSJose E. Roman            if NULL on input, internal storage will be returned, otherwise the provided array is used
36506b867d5aSJose E. Roman 
36516b867d5aSJose E. Roman   Output Parameter:
36526b867d5aSJose E. Roman . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3653552f7358SJed Brown 
3654552f7358SJed Brown   Note:
36550298fd71SBarry Smith   If using internal storage (points is NULL on input), each call overwrites the last output.
3656552f7358SJed Brown 
36573813dfbdSMatthew G Knepley   Fortran Notes:
3658b5a892a1SMatthew G. Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
36593813dfbdSMatthew G Knepley 
36603813dfbdSMatthew G Knepley   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
36613813dfbdSMatthew G Knepley 
3662552f7358SJed Brown   Level: beginner
3663552f7358SJed Brown 
3664db781477SPatrick Sanan .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3665552f7358SJed Brown @*/
3666552f7358SJed Brown PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3667552f7358SJed Brown {
3668b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3669552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3670b5a892a1SMatthew G. Knepley   if (numPoints) PetscValidIntPointer(numPoints, 4);
3671b5a892a1SMatthew G. Knepley   if (points)    PetscValidPointer(points, 5);
36729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
36739bf0dad6SMatthew G. Knepley   PetscFunctionReturn(0);
36749bf0dad6SMatthew G. Knepley }
36759bf0dad6SMatthew G. Knepley 
3676552f7358SJed Brown /*@C
3677eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3678552f7358SJed Brown 
3679552f7358SJed Brown   Not collective
3680552f7358SJed Brown 
3681552f7358SJed Brown   Input Parameters:
3682b5a892a1SMatthew G. Knepley + dm        - The DMPlex
3683b5a892a1SMatthew G. Knepley . p         - The mesh point
3684b5a892a1SMatthew G. Knepley . useCone   - PETSC_TRUE for the closure, otherwise return the star
3685b5a892a1SMatthew G. Knepley . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3686b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3687552f7358SJed Brown 
3688552f7358SJed Brown   Note:
36890298fd71SBarry Smith   If not using internal storage (points is not NULL on input), this call is unnecessary
3690552f7358SJed Brown 
36913813dfbdSMatthew G Knepley   Fortran Notes:
3692b5a892a1SMatthew G. Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
36933813dfbdSMatthew G Knepley 
36943813dfbdSMatthew G Knepley   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
36953813dfbdSMatthew G Knepley 
3696552f7358SJed Brown   Level: beginner
3697552f7358SJed Brown 
3698db781477SPatrick Sanan .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3699552f7358SJed Brown @*/
3700552f7358SJed Brown PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3701552f7358SJed Brown {
3702b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3703552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37044ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
37059566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
3706552f7358SJed Brown   PetscFunctionReturn(0);
3707552f7358SJed Brown }
3708552f7358SJed Brown 
3709552f7358SJed Brown /*@
3710eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3711552f7358SJed Brown 
3712552f7358SJed Brown   Not collective
3713552f7358SJed Brown 
3714552f7358SJed Brown   Input Parameter:
3715552f7358SJed Brown . mesh - The DMPlex
3716552f7358SJed Brown 
3717552f7358SJed Brown   Output Parameters:
3718552f7358SJed Brown + maxConeSize - The maximum number of in-edges
3719552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
3720552f7358SJed Brown 
3721552f7358SJed Brown   Level: beginner
3722552f7358SJed Brown 
3723db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3724552f7358SJed Brown @*/
3725552f7358SJed Brown PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3726552f7358SJed Brown {
3727552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
3728552f7358SJed Brown 
3729552f7358SJed Brown   PetscFunctionBegin;
3730552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37311baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
37321baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
3733552f7358SJed Brown   PetscFunctionReturn(0);
3734552f7358SJed Brown }
3735552f7358SJed Brown 
3736552f7358SJed Brown PetscErrorCode DMSetUp_Plex(DM dm)
3737552f7358SJed Brown {
3738552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
37396302a7fbSVaclav Hapla   PetscInt       size, maxSupportSize;
3740552f7358SJed Brown 
3741552f7358SJed Brown   PetscFunctionBegin;
3742552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37439566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
37449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
37459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
37469566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
37479566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt)));
37486302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
37496302a7fbSVaclav Hapla   if (maxSupportSize) {
37509566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
37519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
37529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
37539566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt)));
3754552f7358SJed Brown   }
3755552f7358SJed Brown   PetscFunctionReturn(0);
3756552f7358SJed Brown }
3757552f7358SJed Brown 
3758276c5506SMatthew G. Knepley PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3759552f7358SJed Brown {
3760552f7358SJed Brown   PetscFunctionBegin;
37619566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
37629566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3763c2939958SSatish Balay   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3764736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
3765f94b4a02SBlaise Bourdin     PetscSF        sfMigrationInv,sfNatural;
3766f94b4a02SBlaise Bourdin     PetscSection   section, sectionSeq;
3767f94b4a02SBlaise Bourdin 
37683dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
37699566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject) dm->sfMigration));
37709566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection((*subdm), &section));
37719566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv));
37729566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq));
37739566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq));
3774f94b4a02SBlaise Bourdin 
37759566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural));
3776c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
37779566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&sectionSeq));
37789566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sfMigrationInv));
3779f94b4a02SBlaise Bourdin   }
3780552f7358SJed Brown   PetscFunctionReturn(0);
3781552f7358SJed Brown }
3782552f7358SJed Brown 
37832adcc780SMatthew G. Knepley PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
37842adcc780SMatthew G. Knepley {
37853dcd263cSBlaise Bourdin   PetscInt       i = 0;
37862adcc780SMatthew G. Knepley 
37872adcc780SMatthew G. Knepley   PetscFunctionBegin;
37889566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
37899566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
3790c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
37913dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
37923dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
37933dcd263cSBlaise Bourdin       PetscSF        sfMigrationInv,sfNatural;
37943dcd263cSBlaise Bourdin       PetscSection   section, sectionSeq;
37953dcd263cSBlaise Bourdin 
37963dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
37979566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration));
3798c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
37999566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection((*superdm), &section));
38009566063dSJacob Faibussowitsch       PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv));
38019566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq));
38029566063dSJacob Faibussowitsch       PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq));
38033dcd263cSBlaise Bourdin 
38049566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural));
3805c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
38069566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&sectionSeq));
38079566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sfMigrationInv));
38083dcd263cSBlaise Bourdin       break;
38093dcd263cSBlaise Bourdin     }
38103dcd263cSBlaise Bourdin   }
38112adcc780SMatthew G. Knepley   PetscFunctionReturn(0);
38122adcc780SMatthew G. Knepley }
38132adcc780SMatthew G. Knepley 
3814552f7358SJed Brown /*@
3815eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3816552f7358SJed Brown 
3817552f7358SJed Brown   Not collective
3818552f7358SJed Brown 
3819552f7358SJed Brown   Input Parameter:
3820552f7358SJed Brown . mesh - The DMPlex
3821552f7358SJed Brown 
3822552f7358SJed Brown   Output Parameter:
3823552f7358SJed Brown 
3824552f7358SJed Brown   Note:
3825552f7358SJed Brown   This should be called after all calls to DMPlexSetCone()
3826552f7358SJed Brown 
3827552f7358SJed Brown   Level: beginner
3828552f7358SJed Brown 
3829db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
3830552f7358SJed Brown @*/
3831552f7358SJed Brown PetscErrorCode DMPlexSymmetrize(DM dm)
3832552f7358SJed Brown {
3833552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3834552f7358SJed Brown   PetscInt      *offsets;
3835552f7358SJed Brown   PetscInt       supportSize;
3836552f7358SJed Brown   PetscInt       pStart, pEnd, p;
3837552f7358SJed Brown 
3838552f7358SJed Brown   PetscFunctionBegin;
3839552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
384028b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
38419566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0));
3842552f7358SJed Brown   /* Calculate support sizes */
38439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3844552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
3845552f7358SJed Brown     PetscInt dof, off, c;
3846552f7358SJed Brown 
38479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
38489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3849552f7358SJed Brown     for (c = off; c < off+dof; ++c) {
38509566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
3851552f7358SJed Brown     }
3852552f7358SJed Brown   }
38539566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
3854552f7358SJed Brown   /* Calculate supports */
38559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
38569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
38579566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
3858552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
3859552f7358SJed Brown     PetscInt dof, off, c;
3860552f7358SJed Brown 
38619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
38629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3863552f7358SJed Brown     for (c = off; c < off+dof; ++c) {
3864552f7358SJed Brown       const PetscInt q = mesh->cones[c];
3865552f7358SJed Brown       PetscInt       offS;
3866552f7358SJed Brown 
38679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
38680d644c17SKarl Rupp 
3869552f7358SJed Brown       mesh->supports[offS+offsets[q]] = p;
3870552f7358SJed Brown       ++offsets[q];
3871552f7358SJed Brown     }
3872552f7358SJed Brown   }
38739566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
38749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0));
3875552f7358SJed Brown   PetscFunctionReturn(0);
3876552f7358SJed Brown }
3877552f7358SJed Brown 
3878277ea44aSLisandro Dalcin static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3879277ea44aSLisandro Dalcin {
3880277ea44aSLisandro Dalcin   IS             stratumIS;
3881277ea44aSLisandro Dalcin 
3882277ea44aSLisandro Dalcin   PetscFunctionBegin;
3883277ea44aSLisandro Dalcin   if (pStart >= pEnd) PetscFunctionReturn(0);
388476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3885277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
3886277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
38879566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
3888277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
38899566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
3890277ea44aSLisandro Dalcin       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3891277ea44aSLisandro Dalcin     }
389263a3b9bcSJacob 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);
3893277ea44aSLisandro Dalcin   }
38949566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS));
38959566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
38969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
3897277ea44aSLisandro Dalcin   PetscFunctionReturn(0);
3898277ea44aSLisandro Dalcin }
3899277ea44aSLisandro Dalcin 
3900552f7358SJed Brown /*@
3901a8d69d7bSBarry Smith   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
39026dd80730SBarry Smith   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3903552f7358SJed Brown   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3904552f7358SJed Brown   the DAG.
3905552f7358SJed Brown 
3906bf4602e4SToby Isaac   Collective on dm
3907552f7358SJed Brown 
3908552f7358SJed Brown   Input Parameter:
3909552f7358SJed Brown . mesh - The DMPlex
3910552f7358SJed Brown 
3911552f7358SJed Brown   Output Parameter:
3912552f7358SJed Brown 
3913552f7358SJed Brown   Notes:
3914b1bb481bSMatthew Knepley   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3915b1bb481bSMatthew 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
3916b1bb481bSMatthew Knepley   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3917c58f1c22SToby Isaac   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3918150b719bSJed Brown   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3919552f7358SJed Brown 
3920b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3921b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3922b1bb481bSMatthew 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
3923b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
3924b1bb481bSMatthew Knepley $  cone(c0) = {e0, v2}
3925b1bb481bSMatthew Knepley $  cone(e0) = {v0, v1}
3926b1bb481bSMatthew Knepley   If DMPlexStratify() is run on this mesh, it will give depths
3927b1bb481bSMatthew Knepley $  depth 0 = {v0, v1, v2}
3928b1bb481bSMatthew Knepley $  depth 1 = {e0, c0}
3929b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3930b1bb481bSMatthew Knepley 
3931150b719bSJed Brown   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3932552f7358SJed Brown 
3933552f7358SJed Brown   Level: beginner
3934552f7358SJed Brown 
3935db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
3936552f7358SJed Brown @*/
3937552f7358SJed Brown PetscErrorCode DMPlexStratify(DM dm)
3938552f7358SJed Brown {
3939df0420ecSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
3940aa50250dSMatthew G. Knepley   DMLabel        label;
3941552f7358SJed Brown   PetscInt       pStart, pEnd, p;
3942552f7358SJed Brown   PetscInt       numRoots = 0, numLeaves = 0;
3943552f7358SJed Brown 
3944552f7358SJed Brown   PetscFunctionBegin;
3945552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
39469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0));
3947277ea44aSLisandro Dalcin 
3948277ea44aSLisandro Dalcin   /* Create depth label */
39499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
39509566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
39519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
3952277ea44aSLisandro Dalcin 
3953277ea44aSLisandro Dalcin   {
3954552f7358SJed Brown     /* Initialize roots and count leaves */
3955277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
3956277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
3957552f7358SJed Brown     PetscInt coneSize, supportSize;
3958552f7358SJed Brown 
3959277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
39609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
39619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
3962552f7358SJed Brown       if (!coneSize && supportSize) {
3963277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
3964277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
3965552f7358SJed Brown         ++numRoots;
3966552f7358SJed Brown       } else if (!supportSize && coneSize) {
3967552f7358SJed Brown         ++numLeaves;
3968552f7358SJed Brown       } else if (!supportSize && !coneSize) {
3969552f7358SJed Brown         /* Isolated points */
3970277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
3971277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
3972552f7358SJed Brown       }
3973552f7358SJed Brown     }
39749566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1));
3975277ea44aSLisandro Dalcin   }
3976277ea44aSLisandro Dalcin 
3977552f7358SJed Brown   if (numRoots + numLeaves == (pEnd - pStart)) {
3978277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
3979277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
3980552f7358SJed Brown     PetscInt coneSize, supportSize;
3981552f7358SJed Brown 
3982277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
39839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
39849566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
3985552f7358SJed Brown       if (!supportSize && coneSize) {
3986277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
3987277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
3988552f7358SJed Brown       }
3989552f7358SJed Brown     }
39909566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1));
3991552f7358SJed Brown   } else {
3992277ea44aSLisandro Dalcin     PetscInt level = 0;
3993277ea44aSLisandro Dalcin     PetscInt qStart, qEnd, q;
3994552f7358SJed Brown 
39959566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
3996277ea44aSLisandro Dalcin     while (qEnd > qStart) {
3997277ea44aSLisandro Dalcin       PetscInt sMin = PETSC_MAX_INT;
3998277ea44aSLisandro Dalcin       PetscInt sMax = PETSC_MIN_INT;
399974ef644bSMatthew G. Knepley 
4000277ea44aSLisandro Dalcin       for (q = qStart; q < qEnd; ++q) {
400174ef644bSMatthew G. Knepley         const PetscInt *support;
400274ef644bSMatthew G. Knepley         PetscInt        supportSize, s;
400374ef644bSMatthew G. Knepley 
40049566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
40059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, q, &support));
400674ef644bSMatthew G. Knepley         for (s = 0; s < supportSize; ++s) {
4007277ea44aSLisandro Dalcin           sMin = PetscMin(support[s], sMin);
4008277ea44aSLisandro Dalcin           sMax = PetscMax(support[s], sMax);
4009552f7358SJed Brown         }
4010552f7358SJed Brown       }
40119566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &level));
40129566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1));
40139566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
401474ef644bSMatthew G. Knepley     }
401574ef644bSMatthew G. Knepley   }
4016bf4602e4SToby Isaac   { /* just in case there is an empty process */
4017bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4018bf4602e4SToby Isaac 
40199566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
40209566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
4021bf4602e4SToby Isaac     for (v = numValues; v < maxValues; v++) {
40229566063dSJacob Faibussowitsch       PetscCall(DMLabelAddStratum(label, v));
4023bf4602e4SToby Isaac     }
4024bf4602e4SToby Isaac   }
40259566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState));
40269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0));
4027552f7358SJed Brown   PetscFunctionReturn(0);
4028552f7358SJed Brown }
4029552f7358SJed Brown 
4030412e9a14SMatthew G. Knepley PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4031ba2698f1SMatthew G. Knepley {
4032412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4033412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4034ba2698f1SMatthew G. Knepley 
4035412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
40369566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
40379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
40389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4039ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4040ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4041ba2698f1SMatthew G. Knepley     switch (pdepth) {
4042ba2698f1SMatthew G. Knepley       case 0: ct = DM_POLYTOPE_POINT;break;
4043ba2698f1SMatthew G. Knepley       case 1:
4044ba2698f1SMatthew G. Knepley         switch (coneSize) {
4045ba2698f1SMatthew G. Knepley           case 2: ct = DM_POLYTOPE_SEGMENT;break;
4046ba2698f1SMatthew G. Knepley           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4047ba2698f1SMatthew G. Knepley           case 4:
4048ba2698f1SMatthew G. Knepley           switch (dim) {
4049ba2698f1SMatthew G. Knepley             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
4050ba2698f1SMatthew G. Knepley             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
4051ba2698f1SMatthew G. Knepley             default: break;
4052ba2698f1SMatthew G. Knepley           }
4053ba2698f1SMatthew G. Knepley           break;
4054da9060c4SMatthew G. Knepley         case 5: ct = DM_POLYTOPE_PYRAMID;break;
4055ba2698f1SMatthew G. Knepley         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4056ba2698f1SMatthew G. Knepley         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
4057ba2698f1SMatthew G. Knepley         default: break;
4058ba2698f1SMatthew G. Knepley       }
4059ba2698f1SMatthew G. Knepley     }
4060ba2698f1SMatthew G. Knepley   } else {
4061ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4062ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4063ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4064ba2698f1SMatthew G. Knepley       switch (dim) {
4065ba2698f1SMatthew G. Knepley         case 1:
4066ba2698f1SMatthew G. Knepley           switch (coneSize) {
4067ba2698f1SMatthew G. Knepley             case 2: ct = DM_POLYTOPE_SEGMENT;break;
4068ba2698f1SMatthew G. Knepley             default: break;
4069ba2698f1SMatthew G. Knepley           }
4070ba2698f1SMatthew G. Knepley           break;
4071ba2698f1SMatthew G. Knepley         case 2:
4072ba2698f1SMatthew G. Knepley           switch (coneSize) {
4073ba2698f1SMatthew G. Knepley             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4074ba2698f1SMatthew G. Knepley             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4075ba2698f1SMatthew G. Knepley             default: break;
4076ba2698f1SMatthew G. Knepley           }
4077ba2698f1SMatthew G. Knepley           break;
4078ba2698f1SMatthew G. Knepley         case 3:
4079ba2698f1SMatthew G. Knepley           switch (coneSize) {
4080ba2698f1SMatthew G. Knepley             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
4081da9060c4SMatthew G. Knepley             case 5:
4082da9060c4SMatthew G. Knepley             {
4083da9060c4SMatthew G. Knepley               const PetscInt *cone;
4084da9060c4SMatthew G. Knepley               PetscInt        faceConeSize;
4085da9060c4SMatthew G. Knepley 
40869566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCone(dm, p, &cone));
40879566063dSJacob Faibussowitsch               PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4088da9060c4SMatthew G. Knepley               switch (faceConeSize) {
4089da9060c4SMatthew G. Knepley                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4090da9060c4SMatthew G. Knepley                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
4091da9060c4SMatthew G. Knepley               }
4092da9060c4SMatthew G. Knepley             }
4093da9060c4SMatthew G. Knepley             break;
4094ba2698f1SMatthew G. Knepley             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
4095ba2698f1SMatthew G. Knepley             default: break;
4096ba2698f1SMatthew G. Knepley           }
4097ba2698f1SMatthew G. Knepley           break;
4098ba2698f1SMatthew G. Knepley         default: break;
4099ba2698f1SMatthew G. Knepley       }
4100ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4101ba2698f1SMatthew G. Knepley       switch (coneSize) {
4102ba2698f1SMatthew G. Knepley         case 2: ct = DM_POLYTOPE_SEGMENT;break;
4103ba2698f1SMatthew G. Knepley         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4104ba2698f1SMatthew G. Knepley         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4105ba2698f1SMatthew G. Knepley         default: break;
4106ba2698f1SMatthew G. Knepley       }
4107ba2698f1SMatthew G. Knepley     }
4108ba2698f1SMatthew G. Knepley   }
4109412e9a14SMatthew G. Knepley   *pt = ct;
4110412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
4111ba2698f1SMatthew G. Knepley }
4112412e9a14SMatthew G. Knepley 
4113412e9a14SMatthew G. Knepley /*@
4114412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4115412e9a14SMatthew G. Knepley 
4116412e9a14SMatthew G. Knepley   Collective on dm
4117412e9a14SMatthew G. Knepley 
4118412e9a14SMatthew G. Knepley   Input Parameter:
4119412e9a14SMatthew G. Knepley . mesh - The DMPlex
4120412e9a14SMatthew G. Knepley 
4121412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4122412e9a14SMatthew G. Knepley 
4123412e9a14SMatthew G. Knepley   Level: developer
4124412e9a14SMatthew G. Knepley 
4125412e9a14SMatthew G. Knepley   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4126412e9a14SMatthew G. Knepley   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4127412e9a14SMatthew G. Knepley   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4128412e9a14SMatthew G. Knepley 
4129db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4130412e9a14SMatthew G. Knepley @*/
4131412e9a14SMatthew G. Knepley PetscErrorCode DMPlexComputeCellTypes(DM dm)
4132412e9a14SMatthew G. Knepley {
4133412e9a14SMatthew G. Knepley   DM_Plex       *mesh;
4134412e9a14SMatthew G. Knepley   DMLabel        ctLabel;
4135412e9a14SMatthew G. Knepley   PetscInt       pStart, pEnd, p;
4136412e9a14SMatthew G. Knepley 
4137412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4138412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4139412e9a14SMatthew G. Knepley   mesh = (DM_Plex *) dm->data;
41409566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
41419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
41429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4143412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4144327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4145412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4146412e9a14SMatthew G. Knepley 
41479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
41489566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
414963a3b9bcSJacob Faibussowitsch     PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p);
41509566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4151412e9a14SMatthew G. Knepley   }
41529566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState));
41539566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view"));
4154ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4155ba2698f1SMatthew G. Knepley }
4156ba2698f1SMatthew G. Knepley 
4157552f7358SJed Brown /*@C
4158552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4159552f7358SJed Brown 
4160552f7358SJed Brown   Not Collective
4161552f7358SJed Brown 
4162552f7358SJed Brown   Input Parameters:
4163552f7358SJed Brown + dm - The DMPlex object
4164552f7358SJed Brown . numPoints - The number of input points for the join
4165552f7358SJed Brown - points - The input points
4166552f7358SJed Brown 
4167552f7358SJed Brown   Output Parameters:
4168552f7358SJed Brown + numCoveredPoints - The number of points in the join
4169552f7358SJed Brown - coveredPoints - The points in the join
4170552f7358SJed Brown 
4171552f7358SJed Brown   Level: intermediate
4172552f7358SJed Brown 
4173552f7358SJed Brown   Note: Currently, this is restricted to a single level join
4174552f7358SJed Brown 
41753813dfbdSMatthew G Knepley   Fortran Notes:
41763813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
41773813dfbdSMatthew G Knepley   include petsc.h90 in your code.
41783813dfbdSMatthew G Knepley 
41793813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
41803813dfbdSMatthew G Knepley 
4181db781477SPatrick Sanan .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4182552f7358SJed Brown @*/
4183552f7358SJed Brown PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4184552f7358SJed Brown {
4185552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
4186552f7358SJed Brown   PetscInt      *join[2];
4187552f7358SJed Brown   PetscInt       joinSize, i = 0;
4188552f7358SJed Brown   PetscInt       dof, off, p, c, m;
41896302a7fbSVaclav Hapla   PetscInt       maxSupportSize;
4190552f7358SJed Brown 
4191552f7358SJed Brown   PetscFunctionBegin;
4192552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
419348bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
419448bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
419548bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
41966302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
41976302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
41986302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4199552f7358SJed Brown   /* Copy in support of first point */
42009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
42019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4202552f7358SJed Brown   for (joinSize = 0; joinSize < dof; ++joinSize) {
4203552f7358SJed Brown     join[i][joinSize] = mesh->supports[off+joinSize];
4204552f7358SJed Brown   }
4205552f7358SJed Brown   /* Check each successive support */
4206552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4207552f7358SJed Brown     PetscInt newJoinSize = 0;
4208552f7358SJed Brown 
42099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
42109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4211552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4212552f7358SJed Brown       const PetscInt point = mesh->supports[off+c];
4213552f7358SJed Brown 
4214552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4215552f7358SJed Brown         if (point == join[i][m]) {
4216552f7358SJed Brown           join[1-i][newJoinSize++] = point;
4217552f7358SJed Brown           break;
4218552f7358SJed Brown         }
4219552f7358SJed Brown       }
4220552f7358SJed Brown     }
4221552f7358SJed Brown     joinSize = newJoinSize;
4222552f7358SJed Brown     i        = 1-i;
4223552f7358SJed Brown   }
4224552f7358SJed Brown   *numCoveredPoints = joinSize;
4225552f7358SJed Brown   *coveredPoints    = join[i];
42266302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i]));
4227552f7358SJed Brown   PetscFunctionReturn(0);
4228552f7358SJed Brown }
4229552f7358SJed Brown 
4230552f7358SJed Brown /*@C
4231552f7358SJed Brown   DMPlexRestoreJoin - Restore an array for the join of the set of points
4232552f7358SJed Brown 
4233552f7358SJed Brown   Not Collective
4234552f7358SJed Brown 
4235552f7358SJed Brown   Input Parameters:
4236552f7358SJed Brown + dm - The DMPlex object
4237552f7358SJed Brown . numPoints - The number of input points for the join
4238552f7358SJed Brown - points - The input points
4239552f7358SJed Brown 
4240552f7358SJed Brown   Output Parameters:
4241552f7358SJed Brown + numCoveredPoints - The number of points in the join
4242552f7358SJed Brown - coveredPoints - The points in the join
4243552f7358SJed Brown 
42443813dfbdSMatthew G Knepley   Fortran Notes:
42453813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
42463813dfbdSMatthew G Knepley   include petsc.h90 in your code.
42473813dfbdSMatthew G Knepley 
42483813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
42493813dfbdSMatthew G Knepley 
4250552f7358SJed Brown   Level: intermediate
4251552f7358SJed Brown 
4252db781477SPatrick Sanan .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4253552f7358SJed Brown @*/
4254552f7358SJed Brown PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4255552f7358SJed Brown {
4256552f7358SJed Brown   PetscFunctionBegin;
4257552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4258d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points,3);
4259d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4260d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints, 5);
42619566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints));
4262d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
4263552f7358SJed Brown   PetscFunctionReturn(0);
4264552f7358SJed Brown }
4265552f7358SJed Brown 
4266552f7358SJed Brown /*@C
4267552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4268552f7358SJed Brown 
4269552f7358SJed Brown   Not Collective
4270552f7358SJed Brown 
4271552f7358SJed Brown   Input Parameters:
4272552f7358SJed Brown + dm - The DMPlex object
4273552f7358SJed Brown . numPoints - The number of input points for the join
4274552f7358SJed Brown - points - The input points
4275552f7358SJed Brown 
4276552f7358SJed Brown   Output Parameters:
4277552f7358SJed Brown + numCoveredPoints - The number of points in the join
4278552f7358SJed Brown - coveredPoints - The points in the join
4279552f7358SJed Brown 
42803813dfbdSMatthew G Knepley   Fortran Notes:
42813813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
42823813dfbdSMatthew G Knepley   include petsc.h90 in your code.
42833813dfbdSMatthew G Knepley 
42843813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
42853813dfbdSMatthew G Knepley 
4286552f7358SJed Brown   Level: intermediate
4287552f7358SJed Brown 
4288db781477SPatrick Sanan .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4289552f7358SJed Brown @*/
4290552f7358SJed Brown PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4291552f7358SJed Brown {
4292552f7358SJed Brown   PetscInt      *offsets, **closures;
4293552f7358SJed Brown   PetscInt      *join[2];
4294552f7358SJed Brown   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
429524c766afSToby Isaac   PetscInt       p, d, c, m, ms;
4296552f7358SJed Brown 
4297552f7358SJed Brown   PetscFunctionBegin;
4298552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
429948bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
430048bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
430148bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
4302552f7358SJed Brown 
43039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
43049566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
43059566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets));
43066302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
430724c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
43089566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
43099566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4310552f7358SJed Brown 
4311552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4312552f7358SJed Brown     PetscInt closureSize;
4313552f7358SJed Brown 
43149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
43150d644c17SKarl Rupp 
4316552f7358SJed Brown     offsets[p*(depth+2)+0] = 0;
4317552f7358SJed Brown     for (d = 0; d < depth+1; ++d) {
4318552f7358SJed Brown       PetscInt pStart, pEnd, i;
4319552f7358SJed Brown 
43209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4321552f7358SJed Brown       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
4322552f7358SJed Brown         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4323552f7358SJed Brown           offsets[p*(depth+2)+d+1] = i;
4324552f7358SJed Brown           break;
4325552f7358SJed Brown         }
4326552f7358SJed Brown       }
4327552f7358SJed Brown       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
4328552f7358SJed Brown     }
432963a3b9bcSJacob 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);
4330552f7358SJed Brown   }
4331552f7358SJed Brown   for (d = 0; d < depth+1; ++d) {
4332552f7358SJed Brown     PetscInt dof;
4333552f7358SJed Brown 
4334552f7358SJed Brown     /* Copy in support of first point */
4335552f7358SJed Brown     dof = offsets[d+1] - offsets[d];
4336552f7358SJed Brown     for (joinSize = 0; joinSize < dof; ++joinSize) {
4337552f7358SJed Brown       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
4338552f7358SJed Brown     }
4339552f7358SJed Brown     /* Check each successive cone */
4340552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4341552f7358SJed Brown       PetscInt newJoinSize = 0;
4342552f7358SJed Brown 
4343552f7358SJed Brown       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
4344552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4345552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
4346552f7358SJed Brown 
4347552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4348552f7358SJed Brown           if (point == join[i][m]) {
4349552f7358SJed Brown             join[1-i][newJoinSize++] = point;
4350552f7358SJed Brown             break;
4351552f7358SJed Brown           }
4352552f7358SJed Brown         }
4353552f7358SJed Brown       }
4354552f7358SJed Brown       joinSize = newJoinSize;
4355552f7358SJed Brown       i        = 1-i;
4356552f7358SJed Brown     }
4357552f7358SJed Brown     if (joinSize) break;
4358552f7358SJed Brown   }
4359552f7358SJed Brown   *numCoveredPoints = joinSize;
4360552f7358SJed Brown   *coveredPoints    = join[i];
4361552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
43629566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4363552f7358SJed Brown   }
43649566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
43659566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets));
43666302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i]));
4367552f7358SJed Brown   PetscFunctionReturn(0);
4368552f7358SJed Brown }
4369552f7358SJed Brown 
4370552f7358SJed Brown /*@C
4371552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4372552f7358SJed Brown 
4373552f7358SJed Brown   Not Collective
4374552f7358SJed Brown 
4375552f7358SJed Brown   Input Parameters:
4376552f7358SJed Brown + dm - The DMPlex object
4377552f7358SJed Brown . numPoints - The number of input points for the meet
4378552f7358SJed Brown - points - The input points
4379552f7358SJed Brown 
4380552f7358SJed Brown   Output Parameters:
4381552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4382552f7358SJed Brown - coveredPoints - The points in the meet
4383552f7358SJed Brown 
4384552f7358SJed Brown   Level: intermediate
4385552f7358SJed Brown 
4386552f7358SJed Brown   Note: Currently, this is restricted to a single level meet
4387552f7358SJed Brown 
43883813dfbdSMatthew G Knepley   Fortran Notes:
43893813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
43903813dfbdSMatthew G Knepley   include petsc.h90 in your code.
43913813dfbdSMatthew G Knepley 
43923813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
43933813dfbdSMatthew G Knepley 
4394db781477SPatrick Sanan .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4395552f7358SJed Brown @*/
4396552f7358SJed Brown PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4397552f7358SJed Brown {
4398552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
4399552f7358SJed Brown   PetscInt      *meet[2];
4400552f7358SJed Brown   PetscInt       meetSize, i = 0;
4401552f7358SJed Brown   PetscInt       dof, off, p, c, m;
44026302a7fbSVaclav Hapla   PetscInt       maxConeSize;
4403552f7358SJed Brown 
4404552f7358SJed Brown   PetscFunctionBegin;
4405552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4406dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4407dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveringPoints, 4);
4408064a246eSJacob Faibussowitsch   PetscValidPointer(coveringPoints, 5);
44096302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
44106302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
44116302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4412552f7358SJed Brown   /* Copy in cone of first point */
44139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
44149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4415552f7358SJed Brown   for (meetSize = 0; meetSize < dof; ++meetSize) {
4416552f7358SJed Brown     meet[i][meetSize] = mesh->cones[off+meetSize];
4417552f7358SJed Brown   }
4418552f7358SJed Brown   /* Check each successive cone */
4419552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4420552f7358SJed Brown     PetscInt newMeetSize = 0;
4421552f7358SJed Brown 
44229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
44239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4424552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4425552f7358SJed Brown       const PetscInt point = mesh->cones[off+c];
4426552f7358SJed Brown 
4427552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
4428552f7358SJed Brown         if (point == meet[i][m]) {
4429552f7358SJed Brown           meet[1-i][newMeetSize++] = point;
4430552f7358SJed Brown           break;
4431552f7358SJed Brown         }
4432552f7358SJed Brown       }
4433552f7358SJed Brown     }
4434552f7358SJed Brown     meetSize = newMeetSize;
4435552f7358SJed Brown     i        = 1-i;
4436552f7358SJed Brown   }
4437552f7358SJed Brown   *numCoveringPoints = meetSize;
4438552f7358SJed Brown   *coveringPoints    = meet[i];
44396302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i]));
4440552f7358SJed Brown   PetscFunctionReturn(0);
4441552f7358SJed Brown }
4442552f7358SJed Brown 
4443552f7358SJed Brown /*@C
4444552f7358SJed Brown   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4445552f7358SJed Brown 
4446552f7358SJed Brown   Not Collective
4447552f7358SJed Brown 
4448552f7358SJed Brown   Input Parameters:
4449552f7358SJed Brown + dm - The DMPlex object
4450552f7358SJed Brown . numPoints - The number of input points for the meet
4451552f7358SJed Brown - points - The input points
4452552f7358SJed Brown 
4453552f7358SJed Brown   Output Parameters:
4454552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4455552f7358SJed Brown - coveredPoints - The points in the meet
4456552f7358SJed Brown 
4457552f7358SJed Brown   Level: intermediate
4458552f7358SJed Brown 
44593813dfbdSMatthew G Knepley   Fortran Notes:
44603813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
44613813dfbdSMatthew G Knepley   include petsc.h90 in your code.
44623813dfbdSMatthew G Knepley 
44633813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
44643813dfbdSMatthew G Knepley 
4465db781477SPatrick Sanan .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4466552f7358SJed Brown @*/
4467552f7358SJed Brown PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4468552f7358SJed Brown {
4469552f7358SJed Brown   PetscFunctionBegin;
4470552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4471d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points,3);
4472d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4473d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints,5);
44749566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints));
4475d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
4476552f7358SJed Brown   PetscFunctionReturn(0);
4477552f7358SJed Brown }
4478552f7358SJed Brown 
4479552f7358SJed Brown /*@C
4480552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
4481552f7358SJed Brown 
4482552f7358SJed Brown   Not Collective
4483552f7358SJed Brown 
4484552f7358SJed Brown   Input Parameters:
4485552f7358SJed Brown + dm - The DMPlex object
4486552f7358SJed Brown . numPoints - The number of input points for the meet
4487552f7358SJed Brown - points - The input points
4488552f7358SJed Brown 
4489552f7358SJed Brown   Output Parameters:
4490552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4491552f7358SJed Brown - coveredPoints - The points in the meet
4492552f7358SJed Brown 
4493552f7358SJed Brown   Level: intermediate
4494552f7358SJed Brown 
44953813dfbdSMatthew G Knepley   Fortran Notes:
44963813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
44973813dfbdSMatthew G Knepley   include petsc.h90 in your code.
44983813dfbdSMatthew G Knepley 
44993813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
45003813dfbdSMatthew G Knepley 
4501db781477SPatrick Sanan .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4502552f7358SJed Brown @*/
4503552f7358SJed Brown PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4504552f7358SJed Brown {
4505552f7358SJed Brown   PetscInt      *offsets, **closures;
4506552f7358SJed Brown   PetscInt      *meet[2];
4507552f7358SJed Brown   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
450824c766afSToby Isaac   PetscInt       p, h, c, m, mc;
4509552f7358SJed Brown 
4510552f7358SJed Brown   PetscFunctionBegin;
4511552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4512dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4513dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveredPoints, 4);
4514064a246eSJacob Faibussowitsch   PetscValidPointer(coveredPoints, 5);
4515552f7358SJed Brown 
45169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
45179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
45189566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets));
45196302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
452024c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
45219566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
45229566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4523552f7358SJed Brown 
4524552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4525552f7358SJed Brown     PetscInt closureSize;
4526552f7358SJed Brown 
45279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
45280d644c17SKarl Rupp 
4529552f7358SJed Brown     offsets[p*(height+2)+0] = 0;
4530552f7358SJed Brown     for (h = 0; h < height+1; ++h) {
4531552f7358SJed Brown       PetscInt pStart, pEnd, i;
4532552f7358SJed Brown 
45339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4534552f7358SJed Brown       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4535552f7358SJed Brown         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4536552f7358SJed Brown           offsets[p*(height+2)+h+1] = i;
4537552f7358SJed Brown           break;
4538552f7358SJed Brown         }
4539552f7358SJed Brown       }
4540552f7358SJed Brown       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4541552f7358SJed Brown     }
454263a3b9bcSJacob 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);
4543552f7358SJed Brown   }
4544552f7358SJed Brown   for (h = 0; h < height+1; ++h) {
4545552f7358SJed Brown     PetscInt dof;
4546552f7358SJed Brown 
4547552f7358SJed Brown     /* Copy in cone of first point */
4548552f7358SJed Brown     dof = offsets[h+1] - offsets[h];
4549552f7358SJed Brown     for (meetSize = 0; meetSize < dof; ++meetSize) {
4550552f7358SJed Brown       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4551552f7358SJed Brown     }
4552552f7358SJed Brown     /* Check each successive cone */
4553552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
4554552f7358SJed Brown       PetscInt newMeetSize = 0;
4555552f7358SJed Brown 
4556552f7358SJed Brown       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4557552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4558552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4559552f7358SJed Brown 
4560552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
4561552f7358SJed Brown           if (point == meet[i][m]) {
4562552f7358SJed Brown             meet[1-i][newMeetSize++] = point;
4563552f7358SJed Brown             break;
4564552f7358SJed Brown           }
4565552f7358SJed Brown         }
4566552f7358SJed Brown       }
4567552f7358SJed Brown       meetSize = newMeetSize;
4568552f7358SJed Brown       i        = 1-i;
4569552f7358SJed Brown     }
4570552f7358SJed Brown     if (meetSize) break;
4571552f7358SJed Brown   }
4572552f7358SJed Brown   *numCoveredPoints = meetSize;
4573552f7358SJed Brown   *coveredPoints    = meet[i];
4574552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
45759566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
4576552f7358SJed Brown   }
45779566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
45789566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets));
45796302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i]));
4580552f7358SJed Brown   PetscFunctionReturn(0);
4581552f7358SJed Brown }
4582552f7358SJed Brown 
45834e3744c5SMatthew G. Knepley /*@C
45844e3744c5SMatthew G. Knepley   DMPlexEqual - Determine if two DMs have the same topology
45854e3744c5SMatthew G. Knepley 
45864e3744c5SMatthew G. Knepley   Not Collective
45874e3744c5SMatthew G. Knepley 
45884e3744c5SMatthew G. Knepley   Input Parameters:
45894e3744c5SMatthew G. Knepley + dmA - A DMPlex object
45904e3744c5SMatthew G. Knepley - dmB - A DMPlex object
45914e3744c5SMatthew G. Knepley 
45924e3744c5SMatthew G. Knepley   Output Parameters:
45934e3744c5SMatthew G. Knepley . equal - PETSC_TRUE if the topologies are identical
45944e3744c5SMatthew G. Knepley 
45954e3744c5SMatthew G. Knepley   Level: intermediate
45964e3744c5SMatthew G. Knepley 
45974e3744c5SMatthew G. Knepley   Notes:
45984e3744c5SMatthew G. Knepley   We are not solving graph isomorphism, so we do not permutation.
45994e3744c5SMatthew G. Knepley 
4600db781477SPatrick Sanan .seealso: `DMPlexGetCone()`
46014e3744c5SMatthew G. Knepley @*/
46024e3744c5SMatthew G. Knepley PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
46034e3744c5SMatthew G. Knepley {
46044e3744c5SMatthew G. Knepley   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
46054e3744c5SMatthew G. Knepley 
46064e3744c5SMatthew G. Knepley   PetscFunctionBegin;
46074e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
46084e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4609dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(equal, 3);
46104e3744c5SMatthew G. Knepley 
46114e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
46129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
46139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
46144e3744c5SMatthew G. Knepley   if (depth != depthB) PetscFunctionReturn(0);
46159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart,  &pEnd));
46169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
46174e3744c5SMatthew G. Knepley   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
46184e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
46194e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
46204e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
46214e3744c5SMatthew G. Knepley 
46229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
46239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
46249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
46259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
46269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
46279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
46284e3744c5SMatthew G. Knepley     if (coneSize != coneSizeB) PetscFunctionReturn(0);
46294e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
46304e3744c5SMatthew G. Knepley       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
46314e3744c5SMatthew G. Knepley       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
46324e3744c5SMatthew G. Knepley     }
46339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
46349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
46359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
46369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
46374e3744c5SMatthew G. Knepley     if (supportSize != supportSizeB) PetscFunctionReturn(0);
46384e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
46394e3744c5SMatthew G. Knepley       if (support[s] != supportB[s]) PetscFunctionReturn(0);
46404e3744c5SMatthew G. Knepley     }
46414e3744c5SMatthew G. Knepley   }
46424e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
46434e3744c5SMatthew G. Knepley   PetscFunctionReturn(0);
46444e3744c5SMatthew G. Knepley }
46454e3744c5SMatthew G. Knepley 
46467cd05799SMatthew G. Knepley /*@C
46477cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
46487cd05799SMatthew G. Knepley 
46497cd05799SMatthew G. Knepley   Not Collective
46507cd05799SMatthew G. Knepley 
46517cd05799SMatthew G. Knepley   Input Parameters:
46527cd05799SMatthew G. Knepley + dm         - The DMPlex
46537cd05799SMatthew G. Knepley . cellDim    - The cell dimension
46547cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
46557cd05799SMatthew G. Knepley 
46567cd05799SMatthew G. Knepley   Output Parameters:
46577cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
46587cd05799SMatthew G. Knepley 
46597cd05799SMatthew G. Knepley   Level: developer
46607cd05799SMatthew G. Knepley 
46617cd05799SMatthew G. Knepley   Notes:
46627cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
46637cd05799SMatthew G. Knepley 
4664db781477SPatrick Sanan .seealso: `DMPlexGetCone()`
46657cd05799SMatthew G. Knepley @*/
466618ad9376SMatthew G. Knepley PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4667a6dfd86eSKarl Rupp {
466882f516ccSBarry Smith   MPI_Comm       comm;
4669552f7358SJed Brown 
4670552f7358SJed Brown   PetscFunctionBegin;
46719566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
4672dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numFaceVertices,4);
4673552f7358SJed Brown   switch (cellDim) {
4674552f7358SJed Brown   case 0:
4675552f7358SJed Brown     *numFaceVertices = 0;
4676552f7358SJed Brown     break;
4677552f7358SJed Brown   case 1:
4678552f7358SJed Brown     *numFaceVertices = 1;
4679552f7358SJed Brown     break;
4680552f7358SJed Brown   case 2:
4681552f7358SJed Brown     switch (numCorners) {
468219436ca2SJed Brown     case 3: /* triangle */
468319436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4684552f7358SJed Brown       break;
468519436ca2SJed Brown     case 4: /* quadrilateral */
468619436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4687552f7358SJed Brown       break;
468819436ca2SJed Brown     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
468919436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4690552f7358SJed Brown       break;
469119436ca2SJed Brown     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
469219436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4693552f7358SJed Brown       break;
4694552f7358SJed Brown     default:
469563a3b9bcSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4696552f7358SJed Brown     }
4697552f7358SJed Brown     break;
4698552f7358SJed Brown   case 3:
4699552f7358SJed Brown     switch (numCorners) {
470019436ca2SJed Brown     case 4: /* tetradehdron */
470119436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
4702552f7358SJed Brown       break;
470319436ca2SJed Brown     case 6: /* tet cohesive cells */
470419436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4705552f7358SJed Brown       break;
470619436ca2SJed Brown     case 8: /* hexahedron */
470719436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4708552f7358SJed Brown       break;
470919436ca2SJed Brown     case 9: /* tet cohesive Lagrange cells */
471019436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4711552f7358SJed Brown       break;
471219436ca2SJed Brown     case 10: /* quadratic tetrahedron */
471319436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4714552f7358SJed Brown       break;
471519436ca2SJed Brown     case 12: /* hex cohesive Lagrange cells */
471619436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4717552f7358SJed Brown       break;
471819436ca2SJed Brown     case 18: /* quadratic tet cohesive Lagrange cells */
471919436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4720552f7358SJed Brown       break;
472119436ca2SJed Brown     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
472219436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
4723552f7358SJed Brown       break;
4724552f7358SJed Brown     default:
472563a3b9bcSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4726552f7358SJed Brown     }
4727552f7358SJed Brown     break;
4728552f7358SJed Brown   default:
472963a3b9bcSJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
4730552f7358SJed Brown   }
4731552f7358SJed Brown   PetscFunctionReturn(0);
4732552f7358SJed Brown }
4733552f7358SJed Brown 
4734552f7358SJed Brown /*@
4735aa50250dSMatthew G. Knepley   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4736552f7358SJed Brown 
4737552f7358SJed Brown   Not Collective
4738552f7358SJed Brown 
4739aa50250dSMatthew G. Knepley   Input Parameter:
4740552f7358SJed Brown . dm    - The DMPlex object
4741552f7358SJed Brown 
4742aa50250dSMatthew G. Knepley   Output Parameter:
4743aa50250dSMatthew G. Knepley . depthLabel - The DMLabel recording point depth
4744552f7358SJed Brown 
4745552f7358SJed Brown   Level: developer
4746552f7358SJed Brown 
4747db781477SPatrick Sanan .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
4748aa50250dSMatthew G. Knepley @*/
4749aa50250dSMatthew G. Knepley PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4750aa50250dSMatthew G. Knepley {
4751aa50250dSMatthew G. Knepley   PetscFunctionBegin;
4752aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4753aa50250dSMatthew G. Knepley   PetscValidPointer(depthLabel, 2);
4754c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
4755aa50250dSMatthew G. Knepley   PetscFunctionReturn(0);
4756aa50250dSMatthew G. Knepley }
4757aa50250dSMatthew G. Knepley 
4758aa50250dSMatthew G. Knepley /*@
4759aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4760aa50250dSMatthew G. Knepley 
4761aa50250dSMatthew G. Knepley   Not Collective
4762aa50250dSMatthew G. Knepley 
4763aa50250dSMatthew G. Knepley   Input Parameter:
4764aa50250dSMatthew G. Knepley . dm    - The DMPlex object
4765aa50250dSMatthew G. Knepley 
4766aa50250dSMatthew G. Knepley   Output Parameter:
4767aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
4768aa50250dSMatthew G. Knepley 
4769aa50250dSMatthew G. Knepley   Level: developer
4770552f7358SJed Brown 
4771b1bb481bSMatthew Knepley   Notes:
4772b1bb481bSMatthew Knepley   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4773dc287ab2SVaclav Hapla   The point depth is described more in detail in DMPlexGetDepthStratum().
4774dc287ab2SVaclav Hapla   An empty mesh gives -1.
4775b1bb481bSMatthew Knepley 
4776db781477SPatrick Sanan .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
4777552f7358SJed Brown @*/
4778552f7358SJed Brown PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4779552f7358SJed Brown {
4780aa50250dSMatthew G. Knepley   DMLabel        label;
4781aa50250dSMatthew G. Knepley   PetscInt       d = 0;
4782552f7358SJed Brown 
4783552f7358SJed Brown   PetscFunctionBegin;
4784552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4785dadcf809SJacob Faibussowitsch   PetscValidIntPointer(depth, 2);
47869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
47879566063dSJacob Faibussowitsch   if (label) PetscCall(DMLabelGetNumValues(label, &d));
4788552f7358SJed Brown   *depth = d-1;
4789552f7358SJed Brown   PetscFunctionReturn(0);
4790552f7358SJed Brown }
4791552f7358SJed Brown 
4792552f7358SJed Brown /*@
4793552f7358SJed Brown   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4794552f7358SJed Brown 
4795552f7358SJed Brown   Not Collective
4796552f7358SJed Brown 
4797552f7358SJed Brown   Input Parameters:
4798552f7358SJed Brown + dm    - The DMPlex object
4799570fa34dSVaclav Hapla - depth - The requested depth
4800552f7358SJed Brown 
4801552f7358SJed Brown   Output Parameters:
4802552f7358SJed Brown + start - The first point at this depth
4803552f7358SJed Brown - end   - One beyond the last point at this depth
4804552f7358SJed Brown 
4805647867b2SJed Brown   Notes:
4806647867b2SJed Brown   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4807647867b2SJed Brown   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4808647867b2SJed Brown   higher dimension, e.g., "edges".
4809647867b2SJed Brown 
4810552f7358SJed Brown   Level: developer
4811552f7358SJed Brown 
4812db781477SPatrick Sanan .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
4813552f7358SJed Brown @*/
4814570fa34dSVaclav Hapla PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
48150adebc6cSBarry Smith {
4816aa50250dSMatthew G. Knepley   DMLabel        label;
481763d1a920SMatthew G. Knepley   PetscInt       pStart, pEnd;
4818552f7358SJed Brown 
4819552f7358SJed Brown   PetscFunctionBegin;
4820552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4821dadcf809SJacob Faibussowitsch   if (start) {PetscValidIntPointer(start, 3); *start = 0;}
4822dadcf809SJacob Faibussowitsch   if (end)   {PetscValidIntPointer(end,   4); *end   = 0;}
48239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
48240d644c17SKarl Rupp   if (pStart == pEnd) PetscFunctionReturn(0);
4825570fa34dSVaclav Hapla   if (depth < 0) {
482663d1a920SMatthew G. Knepley     if (start) *start = pStart;
482763d1a920SMatthew G. Knepley     if (end)   *end   = pEnd;
482863d1a920SMatthew G. Knepley     PetscFunctionReturn(0);
4829552f7358SJed Brown   }
48309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
483128b400f6SJacob Faibussowitsch   PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4832570fa34dSVaclav Hapla   PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
4833552f7358SJed Brown   PetscFunctionReturn(0);
4834552f7358SJed Brown }
4835552f7358SJed Brown 
4836552f7358SJed Brown /*@
4837552f7358SJed Brown   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4838552f7358SJed Brown 
4839552f7358SJed Brown   Not Collective
4840552f7358SJed Brown 
4841552f7358SJed Brown   Input Parameters:
4842552f7358SJed Brown + dm     - The DMPlex object
4843570fa34dSVaclav Hapla - height - The requested height
4844552f7358SJed Brown 
4845552f7358SJed Brown   Output Parameters:
4846552f7358SJed Brown + start - The first point at this height
4847552f7358SJed Brown - end   - One beyond the last point at this height
4848552f7358SJed Brown 
4849647867b2SJed Brown   Notes:
4850647867b2SJed Brown   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4851647867b2SJed Brown   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4852647867b2SJed Brown   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4853647867b2SJed Brown 
4854552f7358SJed Brown   Level: developer
4855552f7358SJed Brown 
4856db781477SPatrick Sanan .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
4857552f7358SJed Brown @*/
4858570fa34dSVaclav Hapla PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
48590adebc6cSBarry Smith {
4860aa50250dSMatthew G. Knepley   DMLabel        label;
486163d1a920SMatthew G. Knepley   PetscInt       depth, pStart, pEnd;
4862552f7358SJed Brown 
4863552f7358SJed Brown   PetscFunctionBegin;
4864552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4865dadcf809SJacob Faibussowitsch   if (start) {PetscValidIntPointer(start, 3); *start = 0;}
4866dadcf809SJacob Faibussowitsch   if (end)   {PetscValidIntPointer(end,   4); *end   = 0;}
48679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
48680d644c17SKarl Rupp   if (pStart == pEnd) PetscFunctionReturn(0);
4869570fa34dSVaclav Hapla   if (height < 0) {
487063d1a920SMatthew G. Knepley     if (start) *start = pStart;
487163d1a920SMatthew G. Knepley     if (end)   *end   = pEnd;
487263d1a920SMatthew G. Knepley     PetscFunctionReturn(0);
4873552f7358SJed Brown   }
48749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
487528b400f6SJacob Faibussowitsch   PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
48769566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(label, &depth));
4877570fa34dSVaclav Hapla   PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end));
4878552f7358SJed Brown   PetscFunctionReturn(0);
4879552f7358SJed Brown }
4880552f7358SJed Brown 
4881ba2698f1SMatthew G. Knepley /*@
4882ba2698f1SMatthew G. Knepley   DMPlexGetPointDepth - Get the depth of a given point
4883ba2698f1SMatthew G. Knepley 
4884ba2698f1SMatthew G. Knepley   Not Collective
4885ba2698f1SMatthew G. Knepley 
4886d8d19677SJose E. Roman   Input Parameters:
4887ba2698f1SMatthew G. Knepley + dm    - The DMPlex object
4888ba2698f1SMatthew G. Knepley - point - The point
4889ba2698f1SMatthew G. Knepley 
4890ba2698f1SMatthew G. Knepley   Output Parameter:
4891ba2698f1SMatthew G. Knepley . depth - The depth of the point
4892ba2698f1SMatthew G. Knepley 
4893ba2698f1SMatthew G. Knepley   Level: intermediate
4894ba2698f1SMatthew G. Knepley 
4895db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
4896ba2698f1SMatthew G. Knepley @*/
4897ba2698f1SMatthew G. Knepley PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4898ba2698f1SMatthew G. Knepley {
4899ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
4900ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
490140a2aa30SMatthew G. Knepley   PetscValidIntPointer(depth, 3);
49029566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
4903ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4904ba2698f1SMatthew G. Knepley }
4905ba2698f1SMatthew G. Knepley 
4906ba2698f1SMatthew G. Knepley /*@
49070c0a32dcSVaclav Hapla   DMPlexGetPointHeight - Get the height of a given point
49080c0a32dcSVaclav Hapla 
49090c0a32dcSVaclav Hapla   Not Collective
49100c0a32dcSVaclav Hapla 
4911d8d19677SJose E. Roman   Input Parameters:
49120c0a32dcSVaclav Hapla + dm    - The DMPlex object
49130c0a32dcSVaclav Hapla - point - The point
49140c0a32dcSVaclav Hapla 
49150c0a32dcSVaclav Hapla   Output Parameter:
49160c0a32dcSVaclav Hapla . height - The height of the point
49170c0a32dcSVaclav Hapla 
49180c0a32dcSVaclav Hapla   Level: intermediate
49190c0a32dcSVaclav Hapla 
4920db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
49210c0a32dcSVaclav Hapla @*/
49220c0a32dcSVaclav Hapla PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
49230c0a32dcSVaclav Hapla {
49240c0a32dcSVaclav Hapla   PetscInt       n, pDepth;
49250c0a32dcSVaclav Hapla 
49260c0a32dcSVaclav Hapla   PetscFunctionBegin;
49270c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49280c0a32dcSVaclav Hapla   PetscValidIntPointer(height, 3);
49299566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
49309566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
49310c0a32dcSVaclav Hapla   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
49320c0a32dcSVaclav Hapla   PetscFunctionReturn(0);
49330c0a32dcSVaclav Hapla }
49340c0a32dcSVaclav Hapla 
49350c0a32dcSVaclav Hapla /*@
4936ba2698f1SMatthew G. Knepley   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4937ba2698f1SMatthew G. Knepley 
4938ba2698f1SMatthew G. Knepley   Not Collective
4939ba2698f1SMatthew G. Knepley 
4940ba2698f1SMatthew G. Knepley   Input Parameter:
4941ba2698f1SMatthew G. Knepley . dm - The DMPlex object
4942ba2698f1SMatthew G. Knepley 
4943ba2698f1SMatthew G. Knepley   Output Parameter:
4944ba2698f1SMatthew G. Knepley . celltypeLabel - The DMLabel recording cell polytope type
4945ba2698f1SMatthew G. Knepley 
4946412e9a14SMatthew G. Knepley   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4947412e9a14SMatthew G. Knepley   DMCreateLabel(dm, "celltype") beforehand.
4948412e9a14SMatthew G. Knepley 
4949ba2698f1SMatthew G. Knepley   Level: developer
4950ba2698f1SMatthew G. Knepley 
4951db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
4952ba2698f1SMatthew G. Knepley @*/
4953ba2698f1SMatthew G. Knepley PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4954ba2698f1SMatthew G. Knepley {
4955ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
4956ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4957ba2698f1SMatthew G. Knepley   PetscValidPointer(celltypeLabel, 2);
49589566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
4959ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
4960ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4961ba2698f1SMatthew G. Knepley }
4962ba2698f1SMatthew G. Knepley 
4963ba2698f1SMatthew G. Knepley /*@
4964ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
4965ba2698f1SMatthew G. Knepley 
4966ba2698f1SMatthew G. Knepley   Not Collective
4967ba2698f1SMatthew G. Knepley 
4968d8d19677SJose E. Roman   Input Parameters:
4969ba2698f1SMatthew G. Knepley + dm   - The DMPlex object
4970ba2698f1SMatthew G. Knepley - cell - The cell
4971ba2698f1SMatthew G. Knepley 
4972ba2698f1SMatthew G. Knepley   Output Parameter:
4973ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
4974ba2698f1SMatthew G. Knepley 
4975ba2698f1SMatthew G. Knepley   Level: intermediate
4976ba2698f1SMatthew G. Knepley 
4977db781477SPatrick Sanan .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
4978ba2698f1SMatthew G. Knepley @*/
4979ba2698f1SMatthew G. Knepley PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4980ba2698f1SMatthew G. Knepley {
4981ba2698f1SMatthew G. Knepley   DMLabel        label;
4982ba2698f1SMatthew G. Knepley   PetscInt       ct;
4983ba2698f1SMatthew G. Knepley 
4984ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
4985ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4986ba2698f1SMatthew G. Knepley   PetscValidPointer(celltype, 3);
49879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
49889566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(label, cell, &ct));
498963a3b9bcSJacob Faibussowitsch   PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
4990ba2698f1SMatthew G. Knepley   *celltype = (DMPolytopeType) ct;
4991ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4992ba2698f1SMatthew G. Knepley }
4993ba2698f1SMatthew G. Knepley 
4994412e9a14SMatthew G. Knepley /*@
4995412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
4996412e9a14SMatthew G. Knepley 
4997412e9a14SMatthew G. Knepley   Not Collective
4998412e9a14SMatthew G. Knepley 
4999412e9a14SMatthew G. Knepley   Input Parameters:
5000412e9a14SMatthew G. Knepley + dm   - The DMPlex object
5001412e9a14SMatthew G. Knepley . cell - The cell
5002412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5003412e9a14SMatthew G. Knepley 
5004412e9a14SMatthew G. Knepley   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
5005412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5006412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5007412e9a14SMatthew G. Knepley   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
5008412e9a14SMatthew G. Knepley 
5009412e9a14SMatthew G. Knepley   Level: advanced
5010412e9a14SMatthew G. Knepley 
5011db781477SPatrick Sanan .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5012412e9a14SMatthew G. Knepley @*/
5013412e9a14SMatthew G. Knepley PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5014412e9a14SMatthew G. Knepley {
5015412e9a14SMatthew G. Knepley   DMLabel        label;
5016412e9a14SMatthew G. Knepley 
5017412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5018412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
50209566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
5021412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
5022412e9a14SMatthew G. Knepley }
5023412e9a14SMatthew G. Knepley 
50240adebc6cSBarry Smith PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
50250adebc6cSBarry Smith {
5026efe440bfSMatthew G. Knepley   PetscSection   section, s;
5027efe440bfSMatthew G. Knepley   Mat            m;
50283e922f36SToby Isaac   PetscInt       maxHeight;
5029552f7358SJed Brown 
5030552f7358SJed Brown   PetscFunctionBegin;
50319566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
50329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
50339566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
50349566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
50359566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
50369566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
50379566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
50389566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
50399566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
50409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&s));
50419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&m));
50428f4c458bSMatthew G. Knepley 
50439566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
50449566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5045552f7358SJed Brown   PetscFunctionReturn(0);
5046552f7358SJed Brown }
5047552f7358SJed Brown 
5048f19dbd58SToby Isaac PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5049f19dbd58SToby Isaac {
50506858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
50516858538eSMatthew G. Knepley   DM  coordsDM,    cellCoordsDM;
5052f19dbd58SToby Isaac 
5053f19dbd58SToby Isaac   PetscFunctionBegin;
5054f19dbd58SToby Isaac   *field = NULL;
50559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
50569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
50576858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
50586858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5059f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
50606858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
50616858538eSMatthew G. Knepley     else                                 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5062f19dbd58SToby Isaac   }
5063f19dbd58SToby Isaac   PetscFunctionReturn(0);
5064f19dbd58SToby Isaac }
5065f19dbd58SToby Isaac 
50667cd05799SMatthew G. Knepley /*@C
50677cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
50687cd05799SMatthew G. Knepley 
50697cd05799SMatthew G. Knepley   Not Collective
50707cd05799SMatthew G. Knepley 
50717cd05799SMatthew G. Knepley   Input Parameters:
50727cd05799SMatthew G. Knepley . dm        - The DMPlex object
50737cd05799SMatthew G. Knepley 
50747cd05799SMatthew G. Knepley   Output Parameter:
50757cd05799SMatthew G. Knepley . section - The PetscSection object
50767cd05799SMatthew G. Knepley 
50777cd05799SMatthew G. Knepley   Level: developer
50787cd05799SMatthew G. Knepley 
5079db781477SPatrick Sanan .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`
50807cd05799SMatthew G. Knepley @*/
50810adebc6cSBarry Smith PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
50820adebc6cSBarry Smith {
5083552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
5084552f7358SJed Brown 
5085552f7358SJed Brown   PetscFunctionBegin;
5086552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5087552f7358SJed Brown   if (section) *section = mesh->coneSection;
5088552f7358SJed Brown   PetscFunctionReturn(0);
5089552f7358SJed Brown }
5090552f7358SJed Brown 
50917cd05799SMatthew G. Knepley /*@C
50927cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
50937cd05799SMatthew G. Knepley 
50947cd05799SMatthew G. Knepley   Not Collective
50957cd05799SMatthew G. Knepley 
50967cd05799SMatthew G. Knepley   Input Parameters:
50977cd05799SMatthew G. Knepley . dm        - The DMPlex object
50987cd05799SMatthew G. Knepley 
50997cd05799SMatthew G. Knepley   Output Parameter:
51007cd05799SMatthew G. Knepley . section - The PetscSection object
51017cd05799SMatthew G. Knepley 
51027cd05799SMatthew G. Knepley   Level: developer
51037cd05799SMatthew G. Knepley 
5104db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`
51057cd05799SMatthew G. Knepley @*/
51068cb4d582SMatthew G. Knepley PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
51078cb4d582SMatthew G. Knepley {
51088cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex*) dm->data;
51098cb4d582SMatthew G. Knepley 
51108cb4d582SMatthew G. Knepley   PetscFunctionBegin;
51118cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51128cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
51138cb4d582SMatthew G. Knepley   PetscFunctionReturn(0);
51148cb4d582SMatthew G. Knepley }
51158cb4d582SMatthew G. Knepley 
51167cd05799SMatthew G. Knepley /*@C
51177cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
51187cd05799SMatthew G. Knepley 
51197cd05799SMatthew G. Knepley   Not Collective
51207cd05799SMatthew G. Knepley 
51217cd05799SMatthew G. Knepley   Input Parameters:
51227cd05799SMatthew G. Knepley . dm        - The DMPlex object
51237cd05799SMatthew G. Knepley 
51247cd05799SMatthew G. Knepley   Output Parameter:
51257cd05799SMatthew G. Knepley . cones - The cone for each point
51267cd05799SMatthew G. Knepley 
51277cd05799SMatthew G. Knepley   Level: developer
51287cd05799SMatthew G. Knepley 
5129db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`
51307cd05799SMatthew G. Knepley @*/
5131a6dfd86eSKarl Rupp PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5132a6dfd86eSKarl Rupp {
5133552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
5134552f7358SJed Brown 
5135552f7358SJed Brown   PetscFunctionBegin;
5136552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5137552f7358SJed Brown   if (cones) *cones = mesh->cones;
5138552f7358SJed Brown   PetscFunctionReturn(0);
5139552f7358SJed Brown }
5140552f7358SJed Brown 
51417cd05799SMatthew G. Knepley /*@C
51427cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
51437cd05799SMatthew G. Knepley 
51447cd05799SMatthew G. Knepley   Not Collective
51457cd05799SMatthew G. Knepley 
51467cd05799SMatthew G. Knepley   Input Parameters:
51477cd05799SMatthew G. Knepley . dm        - The DMPlex object
51487cd05799SMatthew G. Knepley 
51497cd05799SMatthew G. Knepley   Output Parameter:
5150b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
51517cd05799SMatthew G. Knepley 
51527cd05799SMatthew G. Knepley   Level: developer
51537cd05799SMatthew G. Knepley 
5154b5a892a1SMatthew G. Knepley   Notes:
5155b5a892a1SMatthew G. Knepley   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5156b5a892a1SMatthew G. Knepley 
5157b5a892a1SMatthew G. Knepley   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5158b5a892a1SMatthew G. Knepley 
5159db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`
51607cd05799SMatthew G. Knepley @*/
5161a6dfd86eSKarl Rupp PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5162a6dfd86eSKarl Rupp {
5163552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
5164552f7358SJed Brown 
5165552f7358SJed Brown   PetscFunctionBegin;
5166552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5167552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5168552f7358SJed Brown   PetscFunctionReturn(0);
5169552f7358SJed Brown }
5170552f7358SJed Brown 
5171552f7358SJed Brown /******************************** FEM Support **********************************/
5172552f7358SJed Brown 
51739e8305c2SJed Brown /*
51749e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
51759e8305c2SJed Brown  representing a line in the section.
51769e8305c2SJed Brown */
51779e8305c2SJed Brown static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
51789e8305c2SJed Brown {
51799e8305c2SJed Brown   PetscFunctionBeginHot;
51809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5181a433471fSStefano Zampini   if (line < 0) {
5182a433471fSStefano Zampini     *k = 0;
5183a433471fSStefano Zampini     *Nc = 0;
5184a433471fSStefano Zampini   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
51859e8305c2SJed Brown     *k = 1;
51869e8305c2SJed Brown   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
51879e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
51889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
51899e8305c2SJed Brown     *k = *k / *Nc + 1;
51909e8305c2SJed Brown   }
51919e8305c2SJed Brown   PetscFunctionReturn(0);
51929e8305c2SJed Brown }
51939e8305c2SJed Brown 
5194a4355906SMatthew Knepley /*@
5195bc1eb3faSJed Brown 
5196bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5197bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
51981bb6d2a8SBarry Smith   section provided (or the section of the DM).
5199a4355906SMatthew Knepley 
5200a4355906SMatthew Knepley   Input Parameters:
5201a4355906SMatthew Knepley + dm      - The DM
5202a4355906SMatthew Knepley . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5203a4355906SMatthew Knepley - section - The PetscSection to reorder, or NULL for the default section
5204a4355906SMatthew Knepley 
5205a4355906SMatthew Knepley   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5206a4355906SMatthew Knepley   degree of the basis.
5207a4355906SMatthew Knepley 
5208bc1eb3faSJed Brown   Example:
5209bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5210bc1eb3faSJed Brown .vb
5211bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5212bc1eb3faSJed Brown 
5213bc1eb3faSJed Brown   v4 -- e6 -- v3
5214bc1eb3faSJed Brown   |           |
5215bc1eb3faSJed Brown   e7    c0    e8
5216bc1eb3faSJed Brown   |           |
5217bc1eb3faSJed Brown   v1 -- e5 -- v2
5218bc1eb3faSJed Brown .ve
5219bc1eb3faSJed Brown 
5220bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5221bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5222bc1eb3faSJed Brown .vb
5223bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5224bc1eb3faSJed Brown     v1 -> [4]
5225bc1eb3faSJed Brown     ...
5226bc1eb3faSJed Brown     e5 -> [8, 9]
5227bc1eb3faSJed Brown .ve
5228bc1eb3faSJed Brown 
5229bc1eb3faSJed Brown   which corresponds to the dofs
5230bc1eb3faSJed Brown .vb
5231bc1eb3faSJed Brown     6   10  11  7
5232bc1eb3faSJed Brown     13  2   3   15
5233bc1eb3faSJed Brown     12  0   1   14
5234bc1eb3faSJed Brown     4   8   9   5
5235bc1eb3faSJed Brown .ve
5236bc1eb3faSJed Brown 
5237bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5238bc1eb3faSJed Brown .vb
5239bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5240bc1eb3faSJed Brown .ve
5241bc1eb3faSJed Brown 
5242bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5243bc1eb3faSJed Brown .vb
5244bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5245bc1eb3faSJed Brown .ve
5246bc1eb3faSJed Brown 
5247a4355906SMatthew Knepley   Level: developer
5248a4355906SMatthew Knepley 
5249db781477SPatrick Sanan .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5250a4355906SMatthew Knepley @*/
5251bc1eb3faSJed Brown PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
52523194fc30SMatthew G. Knepley {
52537391a63aSMatthew G. Knepley   DMLabel        label;
5254bb197d40SJed Brown   PetscInt       dim, depth = -1, eStart = -1, Nf;
52559e8305c2SJed Brown   PetscBool      vertexchart;
52563194fc30SMatthew G. Knepley 
52573194fc30SMatthew G. Knepley   PetscFunctionBegin;
52589566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
5259a433471fSStefano Zampini   if (dim < 1) PetscFunctionReturn(0);
5260a433471fSStefano Zampini   if (point < 0) {
5261a433471fSStefano Zampini     PetscInt sStart,sEnd;
5262a433471fSStefano Zampini 
52639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5264a433471fSStefano Zampini     point = sEnd-sStart ? sStart : point;
5265a433471fSStefano Zampini   }
52669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
52679566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
52689566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
52697391a63aSMatthew G. Knepley   if (depth == 1) {eStart = point;}
52707391a63aSMatthew G. Knepley   else if  (depth == dim) {
52717391a63aSMatthew G. Knepley     const PetscInt *cone;
52727391a63aSMatthew G. Knepley 
52739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5274d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5275d4e6627bSStefano Zampini     else if (dim == 3) {
5276d4e6627bSStefano Zampini       const PetscInt *cone2;
52779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5278d4e6627bSStefano Zampini       eStart = cone2[0];
527963a3b9bcSJacob 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);
528063a3b9bcSJacob 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);
52819e8305c2SJed Brown   {                             /* Determine whether the chart covers all points or just vertices. */
52829e8305c2SJed Brown     PetscInt pStart,pEnd,cStart,cEnd;
52839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd));
52849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section,&cStart,&cEnd));
5285796d0a68SJed Brown     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5286796d0a68SJed Brown     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5287796d0a68SJed Brown     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
52889e8305c2SJed Brown   }
52899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5290bb197d40SJed Brown   for (PetscInt d=1; d<=dim; d++) {
5291bb197d40SJed Brown     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5292bb197d40SJed Brown     PetscInt *perm;
5293bb197d40SJed Brown 
52943194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
52959566063dSJacob Faibussowitsch       PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5296bb197d40SJed Brown       size += PetscPowInt(k+1, d)*Nc;
52973194fc30SMatthew G. Knepley     }
52989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
52993194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5300bb197d40SJed Brown       switch (d) {
5301babf31e0SJed Brown       case 1:
53029566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5303babf31e0SJed Brown         /*
5304babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5305babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5306babf31e0SJed Brown          */
5307babf31e0SJed Brown         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5308babf31e0SJed Brown         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5309babf31e0SJed Brown         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5310babf31e0SJed Brown         foffset = offset;
5311babf31e0SJed Brown         break;
531289eabcffSMatthew G. Knepley       case 2:
53133194fc30SMatthew 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} */
53149566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
53153194fc30SMatthew G. Knepley         /* The SEM order is
53163194fc30SMatthew G. Knepley 
53173194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
531889eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
53193194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
53203194fc30SMatthew G. Knepley          */
53213194fc30SMatthew G. Knepley         {
53223194fc30SMatthew G. Knepley           const PetscInt of   = 0;
53233194fc30SMatthew G. Knepley           const PetscInt oeb  = of   + PetscSqr(k-1);
53243194fc30SMatthew G. Knepley           const PetscInt oer  = oeb  + (k-1);
53253194fc30SMatthew G. Knepley           const PetscInt oet  = oer  + (k-1);
53263194fc30SMatthew G. Knepley           const PetscInt oel  = oet  + (k-1);
53273194fc30SMatthew G. Knepley           const PetscInt ovlb = oel  + (k-1);
53283194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
53293194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
53303194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
53313194fc30SMatthew G. Knepley           PetscInt       o;
53323194fc30SMatthew G. Knepley 
53333194fc30SMatthew G. Knepley           /* bottom */
53343194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
53353194fc30SMatthew G. Knepley           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
53363194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
53373194fc30SMatthew G. Knepley           /* middle */
53383194fc30SMatthew G. Knepley           for (i = 0; i < k-1; ++i) {
53393194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
53403194fc30SMatthew G. Knepley             for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
53413194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
53423194fc30SMatthew G. Knepley           }
53433194fc30SMatthew G. Knepley           /* top */
53443194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
53453194fc30SMatthew G. Knepley           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
53463194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
53473194fc30SMatthew G. Knepley           foffset = offset;
53483194fc30SMatthew G. Knepley         }
534989eabcffSMatthew G. Knepley         break;
535089eabcffSMatthew G. Knepley       case 3:
535189eabcffSMatthew G. Knepley         /* The original hex closure is
535289eabcffSMatthew G. Knepley 
535389eabcffSMatthew G. Knepley          {c,
535489eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
535589eabcffSMatthew 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,
535689eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
535789eabcffSMatthew G. Knepley          */
53589566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
535989eabcffSMatthew G. Knepley         /* The SEM order is
536089eabcffSMatthew G. Knepley          Bottom Slice
536189eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
536289eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
536389eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
536489eabcffSMatthew G. Knepley 
536589eabcffSMatthew G. Knepley          Middle Slice (j)
536689eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
536789eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
536889eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
536989eabcffSMatthew G. Knepley 
537089eabcffSMatthew G. Knepley          Top Slice
537189eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
537289eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
537389eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
537489eabcffSMatthew G. Knepley          */
537589eabcffSMatthew G. Knepley         {
537689eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
537789eabcffSMatthew G. Knepley           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
537889eabcffSMatthew G. Knepley           const PetscInt oft   = ofb   + PetscSqr(k-1);
537989eabcffSMatthew G. Knepley           const PetscInt off   = oft   + PetscSqr(k-1);
538089eabcffSMatthew G. Knepley           const PetscInt ofk   = off   + PetscSqr(k-1);
538189eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk   + PetscSqr(k-1);
538289eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr   + PetscSqr(k-1);
538389eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl   + PetscSqr(k-1);
538489eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl  + (k-1);
538589eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb  + (k-1);
538689eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr  + (k-1);
538789eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf  + (k-1);
538889eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf  + (k-1);
538989eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr  + (k-1);
539089eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb  + (k-1);
539189eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl  + (k-1);
539289eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf  + (k-1);
539389eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf  + (k-1);
539489eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb  + (k-1);
539589eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb  + (k-1);
539689eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
539789eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
539889eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
539989eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
540089eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
540189eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
540289eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
540389eabcffSMatthew G. Knepley           PetscInt       o, n;
540489eabcffSMatthew G. Knepley 
540589eabcffSMatthew G. Knepley           /* Bottom Slice */
540689eabcffSMatthew G. Knepley           /*   bottom */
540789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
540889eabcffSMatthew G. Knepley           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
540989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
541089eabcffSMatthew G. Knepley           /*   middle */
541189eabcffSMatthew G. Knepley           for (i = 0; i < k-1; ++i) {
541289eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5413316b7f87SMax Rietmann             for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;}
541489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
54153194fc30SMatthew G. Knepley           }
541689eabcffSMatthew G. Knepley           /*   top */
541789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
541889eabcffSMatthew G. Knepley           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
541989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
542089eabcffSMatthew G. Knepley 
542189eabcffSMatthew G. Knepley           /* Middle Slice */
542289eabcffSMatthew G. Knepley           for (j = 0; j < k-1; ++j) {
542389eabcffSMatthew G. Knepley             /*   bottom */
542489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
542589eabcffSMatthew G. Knepley             for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
542689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
542789eabcffSMatthew G. Knepley             /*   middle */
542889eabcffSMatthew G. Knepley             for (i = 0; i < k-1; ++i) {
542989eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
543089eabcffSMatthew G. Knepley               for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset;
543189eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
543289eabcffSMatthew G. Knepley             }
543389eabcffSMatthew G. Knepley             /*   top */
543489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
543589eabcffSMatthew G. Knepley             for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
543689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
543789eabcffSMatthew G. Knepley           }
543889eabcffSMatthew G. Knepley 
543989eabcffSMatthew G. Knepley           /* Top Slice */
544089eabcffSMatthew G. Knepley           /*   bottom */
544189eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
544289eabcffSMatthew G. Knepley           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
544389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
544489eabcffSMatthew G. Knepley           /*   middle */
544589eabcffSMatthew G. Knepley           for (i = 0; i < k-1; ++i) {
544689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
544789eabcffSMatthew G. Knepley             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
544889eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
544989eabcffSMatthew G. Knepley           }
545089eabcffSMatthew G. Knepley           /*   top */
545189eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
545289eabcffSMatthew G. Knepley           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
545389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
545489eabcffSMatthew G. Knepley 
545589eabcffSMatthew G. Knepley           foffset = offset;
545689eabcffSMatthew G. Knepley         }
545789eabcffSMatthew G. Knepley         break;
545863a3b9bcSJacob Faibussowitsch       default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
545989eabcffSMatthew G. Knepley       }
546089eabcffSMatthew G. Knepley     }
546163a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
54623194fc30SMatthew G. Knepley     /* Check permutation */
54633194fc30SMatthew G. Knepley     {
54643194fc30SMatthew G. Knepley       PetscInt *check;
54653194fc30SMatthew G. Knepley 
54669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
54671dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
54681dca8a05SBarry Smith         check[i] = -1;
54691dca8a05SBarry 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]);
54701dca8a05SBarry Smith       }
54713194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
54721dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
54739566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
54743194fc30SMatthew G. Knepley     }
54759566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm));
5476a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5477a05c9aa3SJed Brown       PetscInt *loc_perm;
54789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size*2, &loc_perm));
5479a05c9aa3SJed Brown       for (PetscInt i=0; i<size; i++) {
5480a05c9aa3SJed Brown         loc_perm[i] = perm[i];
5481a05c9aa3SJed Brown         loc_perm[size+i] = size + perm[i];
5482a05c9aa3SJed Brown       }
54839566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm));
5484a05c9aa3SJed Brown     }
5485bb197d40SJed Brown   }
54863194fc30SMatthew G. Knepley   PetscFunctionReturn(0);
54873194fc30SMatthew G. Knepley }
54883194fc30SMatthew G. Knepley 
5489e071409bSToby Isaac PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5490e071409bSToby Isaac {
5491e071409bSToby Isaac   PetscDS        prob;
5492e071409bSToby Isaac   PetscInt       depth, Nf, h;
5493e071409bSToby Isaac   DMLabel        label;
5494e071409bSToby Isaac 
5495e071409bSToby Isaac   PetscFunctionBeginHot;
54969566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
5497e071409bSToby Isaac   Nf      = prob->Nf;
5498e071409bSToby Isaac   label   = dm->depthLabel;
5499e071409bSToby Isaac   *dspace = NULL;
5500e071409bSToby Isaac   if (field < Nf) {
5501e071409bSToby Isaac     PetscObject disc = prob->disc[field];
5502e071409bSToby Isaac 
5503e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
5504e071409bSToby Isaac       PetscDualSpace dsp;
5505e071409bSToby Isaac 
55069566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp));
55079566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label,&depth));
55089566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label,point,&h));
5509e071409bSToby Isaac       h    = depth - 1 - h;
5510e071409bSToby Isaac       if (h) {
55119566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace));
5512e071409bSToby Isaac       } else {
5513e071409bSToby Isaac         *dspace = dsp;
5514e071409bSToby Isaac       }
5515e071409bSToby Isaac     }
5516e071409bSToby Isaac   }
5517e071409bSToby Isaac   PetscFunctionReturn(0);
5518e071409bSToby Isaac }
5519e071409bSToby Isaac 
55209fbee547SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5521a6dfd86eSKarl Rupp {
5522552f7358SJed Brown   PetscScalar    *array, *vArray;
5523d9917b9dSMatthew G. Knepley   const PetscInt *cone, *coneO;
55241a271a75SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5525552f7358SJed Brown 
55261b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
55279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
55289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
55299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
55309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
55313f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
55329df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
55339df71ca4SMatthew G. Knepley       PetscInt dof;
5534d9917b9dSMatthew G. Knepley 
55359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
55369df71ca4SMatthew G. Knepley       size += dof;
55379df71ca4SMatthew G. Knepley     }
55389df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
55399df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
55402a3aaacfSMatthew G. Knepley       PetscInt       dof;
55415a1bb5cfSMatthew G. Knepley 
55425a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
55439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
55445a1bb5cfSMatthew G. Knepley       size += dof;
55455a1bb5cfSMatthew G. Knepley     }
55463f7cbbe7SMatthew G. Knepley     if (!values) {
55473f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
55483f7cbbe7SMatthew G. Knepley       PetscFunctionReturn(0);
55493f7cbbe7SMatthew G. Knepley     }
55509566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5551982e9ed1SMatthew G. Knepley   } else {
5552982e9ed1SMatthew G. Knepley     array = *values;
5553982e9ed1SMatthew G. Knepley   }
55549df71ca4SMatthew G. Knepley   size = 0;
55559566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &vArray));
55569df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
55579df71ca4SMatthew G. Knepley     PetscInt     dof, off, d;
55589df71ca4SMatthew G. Knepley     PetscScalar *varr;
5559d9917b9dSMatthew G. Knepley 
55609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
55619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
55629df71ca4SMatthew G. Knepley     varr = &vArray[off];
55631a271a75SMatthew G. Knepley     for (d = 0; d < dof; ++d, ++offset) {
55641a271a75SMatthew G. Knepley       array[offset] = varr[d];
55659df71ca4SMatthew G. Knepley     }
55669df71ca4SMatthew G. Knepley     size += dof;
55679df71ca4SMatthew G. Knepley   }
55689df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
55699df71ca4SMatthew G. Knepley     const PetscInt cp = cone[p];
55709df71ca4SMatthew G. Knepley     PetscInt       o  = coneO[p];
55715a1bb5cfSMatthew G. Knepley     PetscInt       dof, off, d;
55725a1bb5cfSMatthew G. Knepley     PetscScalar   *varr;
55735a1bb5cfSMatthew G. Knepley 
557452ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
55759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
55769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
55775a1bb5cfSMatthew G. Knepley     varr = &vArray[off];
55785a1bb5cfSMatthew G. Knepley     if (o >= 0) {
55791a271a75SMatthew G. Knepley       for (d = 0; d < dof; ++d, ++offset) {
55801a271a75SMatthew G. Knepley         array[offset] = varr[d];
55815a1bb5cfSMatthew G. Knepley       }
55825a1bb5cfSMatthew G. Knepley     } else {
55831a271a75SMatthew G. Knepley       for (d = dof-1; d >= 0; --d, ++offset) {
55841a271a75SMatthew G. Knepley         array[offset] = varr[d];
55855a1bb5cfSMatthew G. Knepley       }
55865a1bb5cfSMatthew G. Knepley     }
55879df71ca4SMatthew G. Knepley     size += dof;
55885a1bb5cfSMatthew G. Knepley   }
55899566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &vArray));
55909df71ca4SMatthew G. Knepley   if (!*values) {
55915a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
55925a1bb5cfSMatthew G. Knepley     *values = array;
55939df71ca4SMatthew G. Knepley   } else {
559463a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
55958c312ff3SMatthew G. Knepley     *csize = size;
55969df71ca4SMatthew G. Knepley   }
55975a1bb5cfSMatthew G. Knepley   PetscFunctionReturn(0);
55985a1bb5cfSMatthew G. Knepley }
5599d9917b9dSMatthew G. Knepley 
560027f02ce8SMatthew G. Knepley /* Compress out points not in the section */
56019fbee547SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
560227f02ce8SMatthew G. Knepley {
560327f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
560427f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
560527f02ce8SMatthew G. Knepley 
56069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
560727f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
560827f02ce8SMatthew G. Knepley     const PetscInt r = points[p*2];
560927f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
561027f02ce8SMatthew G. Knepley       points[q*2]   = r;
561127f02ce8SMatthew G. Knepley       points[q*2+1] = points[p*2+1];
561227f02ce8SMatthew G. Knepley       ++q;
561327f02ce8SMatthew G. Knepley     }
561427f02ce8SMatthew G. Knepley   }
561527f02ce8SMatthew G. Knepley   *numPoints = q;
561627f02ce8SMatthew G. Knepley   return 0;
561727f02ce8SMatthew G. Knepley }
561827f02ce8SMatthew G. Knepley 
561997529cf3SJed Brown /* Compressed closure does not apply closure permutation */
56201dc59d61SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5621923c78e0SToby Isaac {
562227f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
5623923c78e0SToby Isaac   PetscInt       np, *pts = NULL;
5624923c78e0SToby Isaac 
5625923c78e0SToby Isaac   PetscFunctionBeginHot;
56269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints));
562727f02ce8SMatthew G. Knepley   if (*clPoints) {
5628923c78e0SToby Isaac     PetscInt dof, off;
5629923c78e0SToby Isaac 
56309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
56319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
56329566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
5633923c78e0SToby Isaac     np   = dof/2;
5634923c78e0SToby Isaac     pts  = (PetscInt *) &cla[off];
563527f02ce8SMatthew G. Knepley   } else {
56369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts));
56379566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
5638923c78e0SToby Isaac   }
5639923c78e0SToby Isaac   *numPoints = np;
5640923c78e0SToby Isaac   *points    = pts;
5641923c78e0SToby Isaac   *clp       = cla;
5642923c78e0SToby Isaac   PetscFunctionReturn(0);
5643923c78e0SToby Isaac }
5644923c78e0SToby Isaac 
56451dc59d61SMatthew G. Knepley PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5646923c78e0SToby Isaac {
5647923c78e0SToby Isaac   PetscFunctionBeginHot;
5648923c78e0SToby Isaac   if (!*clPoints) {
56499566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5650923c78e0SToby Isaac   } else {
56519566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
5652923c78e0SToby Isaac   }
5653923c78e0SToby Isaac   *numPoints = 0;
5654923c78e0SToby Isaac   *points    = NULL;
5655923c78e0SToby Isaac   *clSec     = NULL;
5656923c78e0SToby Isaac   *clPoints  = NULL;
5657923c78e0SToby Isaac   *clp       = NULL;
5658923c78e0SToby Isaac   PetscFunctionReturn(0);
5659923c78e0SToby Isaac }
5660923c78e0SToby Isaac 
56619fbee547SJacob 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[])
56621a271a75SMatthew G. Knepley {
56631a271a75SMatthew G. Knepley   PetscInt          offset = 0, p;
566497e99dd9SToby Isaac   const PetscInt    **perms = NULL;
566597e99dd9SToby Isaac   const PetscScalar **flips = NULL;
56661a271a75SMatthew G. Knepley 
56671a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5668fe02ba77SJed Brown   *size = 0;
56699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips));
567097e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
567197e99dd9SToby Isaac     const PetscInt    point = points[2*p];
567297e99dd9SToby Isaac     const PetscInt    *perm = perms ? perms[p] : NULL;
567397e99dd9SToby Isaac     const PetscScalar *flip = flips ? flips[p] : NULL;
56741a271a75SMatthew G. Knepley     PetscInt          dof, off, d;
56751a271a75SMatthew G. Knepley     const PetscScalar *varr;
56761a271a75SMatthew G. Knepley 
56779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
56789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
56791a271a75SMatthew G. Knepley     varr = &vArray[off];
568097e99dd9SToby Isaac     if (clperm) {
568197e99dd9SToby Isaac       if (perm) {
568297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
56831a271a75SMatthew G. Knepley       } else {
568497e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
568597e99dd9SToby Isaac       }
568697e99dd9SToby Isaac       if (flip) {
568797e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
568897e99dd9SToby Isaac       }
568997e99dd9SToby Isaac     } else {
569097e99dd9SToby Isaac       if (perm) {
569197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
569297e99dd9SToby Isaac       } else {
569397e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
569497e99dd9SToby Isaac       }
569597e99dd9SToby Isaac       if (flip) {
569697e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
56971a271a75SMatthew G. Knepley       }
56981a271a75SMatthew G. Knepley     }
569997e99dd9SToby Isaac     offset += dof;
570097e99dd9SToby Isaac   }
57019566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips));
57021a271a75SMatthew G. Knepley   *size = offset;
57031a271a75SMatthew G. Knepley   PetscFunctionReturn(0);
57041a271a75SMatthew G. Knepley }
57051a271a75SMatthew G. Knepley 
57069fbee547SJacob 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[])
57071a271a75SMatthew G. Knepley {
57081a271a75SMatthew G. Knepley   PetscInt          offset = 0, f;
57091a271a75SMatthew G. Knepley 
57101a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5711fe02ba77SJed Brown   *size = 0;
57121a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
571397e99dd9SToby Isaac     PetscInt          p;
571497e99dd9SToby Isaac     const PetscInt    **perms = NULL;
571597e99dd9SToby Isaac     const PetscScalar **flips = NULL;
57161a271a75SMatthew G. Knepley 
57179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
571897e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
571997e99dd9SToby Isaac       const PetscInt    point = points[2*p];
572097e99dd9SToby Isaac       PetscInt          fdof, foff, b;
57211a271a75SMatthew G. Knepley       const PetscScalar *varr;
572297e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
572397e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
57241a271a75SMatthew G. Knepley 
57259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
57269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
57271a271a75SMatthew G. Knepley       varr = &vArray[foff];
572897e99dd9SToby Isaac       if (clperm) {
572997e99dd9SToby Isaac         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
573097e99dd9SToby Isaac         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
573197e99dd9SToby Isaac         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
57321a271a75SMatthew G. Knepley       } else {
573397e99dd9SToby Isaac         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
573497e99dd9SToby Isaac         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
573597e99dd9SToby Isaac         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
57361a271a75SMatthew G. Knepley       }
573797e99dd9SToby Isaac       offset += fdof;
57381a271a75SMatthew G. Knepley     }
57399566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
57401a271a75SMatthew G. Knepley   }
57411a271a75SMatthew G. Knepley   *size = offset;
57421a271a75SMatthew G. Knepley   PetscFunctionReturn(0);
57431a271a75SMatthew G. Knepley }
57441a271a75SMatthew G. Knepley 
5745552f7358SJed Brown /*@C
5746552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5747552f7358SJed Brown 
5748552f7358SJed Brown   Not collective
5749552f7358SJed Brown 
5750552f7358SJed Brown   Input Parameters:
5751552f7358SJed Brown + dm - The DM
5752552f7358SJed Brown . section - The section describing the layout in v, or NULL to use the default section
5753552f7358SJed Brown . v - The local vector
57546b867d5aSJose E. Roman - point - The point in the DM
5755552f7358SJed Brown 
57566b867d5aSJose E. Roman   Input/Output Parameters:
57576b867d5aSJose E. Roman + csize  - The size of the input values array, or NULL; on output the number of values in the closure
57586b867d5aSJose E. Roman - values - An array to use for the values, or NULL to have it allocated automatically;
57596b867d5aSJose E. Roman            if the user provided NULL, it is a borrowed array and should not be freed
576022c1ee49SMatthew G. Knepley 
576122c1ee49SMatthew G. Knepley $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
576222c1ee49SMatthew G. Knepley $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
576322c1ee49SMatthew G. Knepley $ assembly function, and a user may already have allocated storage for this operation.
576422c1ee49SMatthew G. Knepley $
576522c1ee49SMatthew G. Knepley $ A typical use could be
576622c1ee49SMatthew G. Knepley $
576722c1ee49SMatthew G. Knepley $  values = NULL;
57689566063dSJacob Faibussowitsch $  PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
576922c1ee49SMatthew G. Knepley $  for (cl = 0; cl < clSize; ++cl) {
577022c1ee49SMatthew G. Knepley $    <Compute on closure>
577122c1ee49SMatthew G. Knepley $  }
57729566063dSJacob Faibussowitsch $  PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
577322c1ee49SMatthew G. Knepley $
577422c1ee49SMatthew G. Knepley $ or
577522c1ee49SMatthew G. Knepley $
577622c1ee49SMatthew G. Knepley $  PetscMalloc1(clMaxSize, &values);
577722c1ee49SMatthew G. Knepley $  for (p = pStart; p < pEnd; ++p) {
577822c1ee49SMatthew G. Knepley $    clSize = clMaxSize;
57799566063dSJacob Faibussowitsch $    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
578022c1ee49SMatthew G. Knepley $    for (cl = 0; cl < clSize; ++cl) {
578122c1ee49SMatthew G. Knepley $      <Compute on closure>
578222c1ee49SMatthew G. Knepley $    }
578322c1ee49SMatthew G. Knepley $  }
578422c1ee49SMatthew G. Knepley $  PetscFree(values);
5785552f7358SJed Brown 
5786552f7358SJed Brown   Fortran Notes:
5787552f7358SJed Brown   Since it returns an array, this routine is only available in Fortran 90, and you must
5788552f7358SJed Brown   include petsc.h90 in your code.
5789552f7358SJed Brown 
5790552f7358SJed Brown   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5791552f7358SJed Brown 
5792552f7358SJed Brown   Level: intermediate
5793552f7358SJed Brown 
5794db781477SPatrick Sanan .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
5795552f7358SJed Brown @*/
5796552f7358SJed Brown PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5797552f7358SJed Brown {
5798552f7358SJed Brown   PetscSection       clSection;
5799d9917b9dSMatthew G. Knepley   IS                 clPoints;
5800552f7358SJed Brown   PetscInt          *points = NULL;
5801c459fbc1SJed Brown   const PetscInt    *clp, *perm;
5802c459fbc1SJed Brown   PetscInt           depth, numFields, numPoints, asize;
5803552f7358SJed Brown 
5804d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
5805552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58069566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
58071a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
58081a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
58099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
58109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
5811552f7358SJed Brown   if (depth == 1 && numFields < 2) {
58129566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
5813552f7358SJed Brown     PetscFunctionReturn(0);
5814552f7358SJed Brown   }
58151a271a75SMatthew G. Knepley   /* Get points */
58169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5817c459fbc1SJed Brown   /* Get sizes */
5818c459fbc1SJed Brown   asize = 0;
5819c459fbc1SJed Brown   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5820c459fbc1SJed Brown     PetscInt dof;
58219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
58221a271a75SMatthew G. Knepley     asize += dof;
5823552f7358SJed Brown   }
5824c459fbc1SJed Brown   if (values) {
5825c459fbc1SJed Brown     const PetscScalar *vArray;
5826c459fbc1SJed Brown     PetscInt          size;
5827c459fbc1SJed Brown 
5828c459fbc1SJed Brown     if (*values) {
582963a3b9bcSJacob 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);
58309566063dSJacob Faibussowitsch     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
58319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm));
58329566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, &vArray));
58331a271a75SMatthew G. Knepley     /* Get values */
58349566063dSJacob Faibussowitsch     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
58359566063dSJacob Faibussowitsch     else               PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
583663a3b9bcSJacob Faibussowitsch     PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
58371a271a75SMatthew G. Knepley     /* Cleanup array */
58389566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, &vArray));
5839d0f6b257SMatthew G. Knepley   }
5840c459fbc1SJed Brown   if (csize) *csize = asize;
5841c459fbc1SJed Brown   /* Cleanup points */
58429566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5843552f7358SJed Brown   PetscFunctionReturn(0);
5844552f7358SJed Brown }
5845552f7358SJed Brown 
5846e5c487bfSMatthew G. Knepley PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5847e5c487bfSMatthew G. Knepley {
5848e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
5849e5c487bfSMatthew G. Knepley   PetscSection       clSection;
5850e5c487bfSMatthew G. Knepley   IS                 clPoints;
5851e5c487bfSMatthew G. Knepley   PetscScalar       *array;
5852e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
5853e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
5854c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
5855c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5856e5c487bfSMatthew G. Knepley 
5857e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
5858e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58599566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
5860e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5861e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
58629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
58639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
58649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
5865e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
58669566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
5867e5c487bfSMatthew G. Knepley     PetscFunctionReturn(0);
5868e5c487bfSMatthew G. Knepley   }
5869e5c487bfSMatthew G. Knepley   /* Get points */
58709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5871c459fbc1SJed Brown   for (clsize=0,p=0; p<Np; p++) {
5872c459fbc1SJed Brown     PetscInt dof;
58739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2*p], &dof));
5874c459fbc1SJed Brown     clsize += dof;
5875c459fbc1SJed Brown   }
58769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm));
5877e5c487bfSMatthew G. Knepley   /* Filter points */
5878e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints*2; p += 2) {
5879e5c487bfSMatthew G. Knepley     PetscInt dep;
5880e5c487bfSMatthew G. Knepley 
58819566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
5882e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
5883e5c487bfSMatthew G. Knepley     points[Np*2+0] = points[p];
5884e5c487bfSMatthew G. Knepley     points[Np*2+1] = points[p+1];
5885e5c487bfSMatthew G. Knepley     ++Np;
5886e5c487bfSMatthew G. Knepley   }
5887e5c487bfSMatthew G. Knepley   /* Get array */
5888e5c487bfSMatthew G. Knepley   if (!values || !*values) {
5889e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
5890e5c487bfSMatthew G. Knepley 
5891e5c487bfSMatthew G. Knepley     for (p = 0; p < Np*2; p += 2) {
58929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
5893e5c487bfSMatthew G. Knepley       asize += dof;
5894e5c487bfSMatthew G. Knepley     }
5895e5c487bfSMatthew G. Knepley     if (!values) {
58969566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5897e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
5898e5c487bfSMatthew G. Knepley       PetscFunctionReturn(0);
5899e5c487bfSMatthew G. Knepley     }
59009566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
5901e5c487bfSMatthew G. Knepley   } else {
5902e5c487bfSMatthew G. Knepley     array = *values;
5903e5c487bfSMatthew G. Knepley   }
59049566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
5905e5c487bfSMatthew G. Knepley   /* Get values */
59069566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
59079566063dSJacob Faibussowitsch   else               PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
5908e5c487bfSMatthew G. Knepley   /* Cleanup points */
59099566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5910e5c487bfSMatthew G. Knepley   /* Cleanup array */
59119566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
5912e5c487bfSMatthew G. Knepley   if (!*values) {
5913e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
5914e5c487bfSMatthew G. Knepley     *values = array;
5915e5c487bfSMatthew G. Knepley   } else {
591663a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
5917e5c487bfSMatthew G. Knepley     *csize = size;
5918e5c487bfSMatthew G. Knepley   }
5919e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
5920e5c487bfSMatthew G. Knepley }
5921e5c487bfSMatthew G. Knepley 
5922552f7358SJed Brown /*@C
5923552f7358SJed Brown   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5924552f7358SJed Brown 
5925552f7358SJed Brown   Not collective
5926552f7358SJed Brown 
5927552f7358SJed Brown   Input Parameters:
5928552f7358SJed Brown + dm - The DM
59290298fd71SBarry Smith . section - The section describing the layout in v, or NULL to use the default section
5930552f7358SJed Brown . v - The local vector
5931eaf898f9SPatrick Sanan . point - The point in the DM
59320298fd71SBarry Smith . csize - The number of values in the closure, or NULL
5933552f7358SJed Brown - values - The array of values, which is a borrowed array and should not be freed
5934552f7358SJed Brown 
593522c1ee49SMatthew 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()
593622c1ee49SMatthew G. Knepley 
59373813dfbdSMatthew G Knepley   Fortran Notes:
59383813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
59393813dfbdSMatthew G Knepley   include petsc.h90 in your code.
59403813dfbdSMatthew G Knepley 
59413813dfbdSMatthew G Knepley   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
59423813dfbdSMatthew G Knepley 
5943552f7358SJed Brown   Level: intermediate
5944552f7358SJed Brown 
5945db781477SPatrick Sanan .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
5946552f7358SJed Brown @*/
59477c1f9639SMatthew G Knepley PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5948a6dfd86eSKarl Rupp {
5949552f7358SJed Brown   PetscInt       size = 0;
5950552f7358SJed Brown 
5951552f7358SJed Brown   PetscFunctionBegin;
5952552f7358SJed Brown   /* Should work without recalculating size */
59539566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values));
5954c9fdaa05SMatthew G. Knepley   *values = NULL;
5955552f7358SJed Brown   PetscFunctionReturn(0);
5956552f7358SJed Brown }
5957552f7358SJed Brown 
59589fbee547SJacob Faibussowitsch static inline void add   (PetscScalar *x, PetscScalar y) {*x += y;}
59599fbee547SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5960552f7358SJed Brown 
59619fbee547SJacob 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[])
5962552f7358SJed Brown {
5963552f7358SJed Brown   PetscInt        cdof;   /* The number of constraints on this point */
5964552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5965552f7358SJed Brown   PetscScalar    *a;
5966552f7358SJed Brown   PetscInt        off, cind = 0, k;
5967552f7358SJed Brown 
5968552f7358SJed Brown   PetscFunctionBegin;
59699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
59709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
5971552f7358SJed Brown   a    = &array[off];
5972552f7358SJed Brown   if (!cdof || setBC) {
597397e99dd9SToby Isaac     if (clperm) {
597497e99dd9SToby Isaac       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
597597e99dd9SToby Isaac       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5976552f7358SJed Brown     } else {
597797e99dd9SToby Isaac       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
597897e99dd9SToby Isaac       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5979552f7358SJed Brown     }
5980552f7358SJed Brown   } else {
59819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
598297e99dd9SToby Isaac     if (clperm) {
598397e99dd9SToby Isaac       if (perm) {for (k = 0; k < dof; ++k) {
5984552f7358SJed Brown           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
598597e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5986552f7358SJed Brown         }
5987552f7358SJed Brown       } else {
5988552f7358SJed Brown         for (k = 0; k < dof; ++k) {
5989552f7358SJed Brown           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
599097e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
599197e99dd9SToby Isaac         }
599297e99dd9SToby Isaac       }
599397e99dd9SToby Isaac     } else {
599497e99dd9SToby Isaac       if (perm) {
599597e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
599697e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
599797e99dd9SToby Isaac           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
599897e99dd9SToby Isaac         }
599997e99dd9SToby Isaac       } else {
600097e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
600197e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
600297e99dd9SToby Isaac           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
600397e99dd9SToby Isaac         }
6004552f7358SJed Brown       }
6005552f7358SJed Brown     }
6006552f7358SJed Brown   }
6007552f7358SJed Brown   PetscFunctionReturn(0);
6008552f7358SJed Brown }
6009552f7358SJed Brown 
60109fbee547SJacob 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[])
6011a5e93ea8SMatthew G. Knepley {
6012a5e93ea8SMatthew G. Knepley   PetscInt        cdof;   /* The number of constraints on this point */
6013a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6014a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6015a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6016a5e93ea8SMatthew G. Knepley 
6017a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
60189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
60199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6020a5e93ea8SMatthew G. Knepley   a    = &array[off];
6021a5e93ea8SMatthew G. Knepley   if (cdof) {
60229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
602397e99dd9SToby Isaac     if (clperm) {
602497e99dd9SToby Isaac       if (perm) {
6025a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6026a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
602797e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
602897e99dd9SToby Isaac             cind++;
6029a5e93ea8SMatthew G. Knepley           }
6030a5e93ea8SMatthew G. Knepley         }
6031a5e93ea8SMatthew G. Knepley       } else {
6032a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6033a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
603497e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
603597e99dd9SToby Isaac             cind++;
603697e99dd9SToby Isaac           }
603797e99dd9SToby Isaac         }
603897e99dd9SToby Isaac       }
603997e99dd9SToby Isaac     } else {
604097e99dd9SToby Isaac       if (perm) {
604197e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
604297e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
604397e99dd9SToby Isaac             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
604497e99dd9SToby Isaac             cind++;
604597e99dd9SToby Isaac           }
604697e99dd9SToby Isaac         }
604797e99dd9SToby Isaac       } else {
604897e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
604997e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
605097e99dd9SToby Isaac             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
605197e99dd9SToby Isaac             cind++;
605297e99dd9SToby Isaac           }
6053a5e93ea8SMatthew G. Knepley         }
6054a5e93ea8SMatthew G. Knepley       }
6055a5e93ea8SMatthew G. Knepley     }
6056a5e93ea8SMatthew G. Knepley   }
6057a5e93ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6058a5e93ea8SMatthew G. Knepley }
6059a5e93ea8SMatthew G. Knepley 
60609fbee547SJacob 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[])
6061a6dfd86eSKarl Rupp {
6062552f7358SJed Brown   PetscScalar    *a;
60631a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
60641a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
606597e99dd9SToby Isaac   PetscInt        cind = 0, b;
6066552f7358SJed Brown 
6067552f7358SJed Brown   PetscFunctionBegin;
60689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
60699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
60709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
60711a271a75SMatthew G. Knepley   a    = &array[foff];
6072552f7358SJed Brown   if (!fcdof || setBC) {
607397e99dd9SToby Isaac     if (clperm) {
607497e99dd9SToby Isaac       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
607597e99dd9SToby Isaac       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
6076552f7358SJed Brown     } else {
607797e99dd9SToby Isaac       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
607897e99dd9SToby Isaac       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
6079552f7358SJed Brown     }
6080552f7358SJed Brown   } else {
60819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
608297e99dd9SToby Isaac     if (clperm) {
608397e99dd9SToby Isaac       if (perm) {
608497e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
608597e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
608697e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6087552f7358SJed Brown         }
6088552f7358SJed Brown       } else {
608997e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
609097e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
609197e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
609297e99dd9SToby Isaac         }
609397e99dd9SToby Isaac       }
609497e99dd9SToby Isaac     } else {
609597e99dd9SToby Isaac       if (perm) {
609697e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
609797e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
609897e99dd9SToby Isaac           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
609997e99dd9SToby Isaac         }
610097e99dd9SToby Isaac       } else {
610197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
610297e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
610397e99dd9SToby Isaac           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6104552f7358SJed Brown         }
6105552f7358SJed Brown       }
6106552f7358SJed Brown     }
6107552f7358SJed Brown   }
61081a271a75SMatthew G. Knepley   *offset += fdof;
6109552f7358SJed Brown   PetscFunctionReturn(0);
6110552f7358SJed Brown }
6111552f7358SJed Brown 
61129fbee547SJacob 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[])
6113a5e93ea8SMatthew G. Knepley {
6114a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
61151a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
61161a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
61175da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6118ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6119a5e93ea8SMatthew G. Knepley 
6120a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
61219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
61229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
61239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
61249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
61251a271a75SMatthew G. Knepley   a    = &array[foff];
6126a5e93ea8SMatthew G. Knepley   if (fcdof) {
6127ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
61289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
612997e99dd9SToby Isaac     if (clperm) {
613097e99dd9SToby Isaac       if (perm) {
6131ba322698SMatthew G. Knepley         if (comps) {
6132ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6133ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61345da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6135ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6136ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6137ba322698SMatthew G. Knepley           }
6138ba322698SMatthew G. Knepley         } else {
613997e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
614097e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
614197e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6142a5e93ea8SMatthew G. Knepley               ++cind;
6143a5e93ea8SMatthew G. Knepley             }
6144a5e93ea8SMatthew G. Knepley           }
6145ba322698SMatthew G. Knepley         }
6146ba322698SMatthew G. Knepley       } else {
6147ba322698SMatthew G. Knepley         if (comps) {
6148ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6149ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61505da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6151ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6152ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6153ba322698SMatthew G. Knepley           }
6154a5e93ea8SMatthew G. Knepley         } else {
615597e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
615697e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
615797e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
615897e99dd9SToby Isaac               ++cind;
615997e99dd9SToby Isaac             }
616097e99dd9SToby Isaac           }
616197e99dd9SToby Isaac         }
6162ba322698SMatthew G. Knepley       }
616397e99dd9SToby Isaac     } else {
616497e99dd9SToby Isaac       if (perm) {
6165ba322698SMatthew G. Knepley         if (comps) {
6166ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6167ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61685da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6169ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6170ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6171ba322698SMatthew G. Knepley           }
6172ba322698SMatthew G. Knepley         } else {
617397e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
617497e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
617597e99dd9SToby Isaac               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
617697e99dd9SToby Isaac               ++cind;
617797e99dd9SToby Isaac             }
617897e99dd9SToby Isaac           }
6179ba322698SMatthew G. Knepley         }
6180ba322698SMatthew G. Knepley       } else {
6181ba322698SMatthew G. Knepley         if (comps) {
6182ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6183ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61845da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6185ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6186ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6187ba322698SMatthew G. Knepley           }
618897e99dd9SToby Isaac         } else {
618997e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
619097e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
619197e99dd9SToby Isaac               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6192a5e93ea8SMatthew G. Knepley               ++cind;
6193a5e93ea8SMatthew G. Knepley             }
6194a5e93ea8SMatthew G. Knepley           }
6195a5e93ea8SMatthew G. Knepley         }
6196a5e93ea8SMatthew G. Knepley       }
6197a5e93ea8SMatthew G. Knepley     }
6198ba322698SMatthew G. Knepley   }
61991a271a75SMatthew G. Knepley   *offset += fdof;
6200a5e93ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6201a5e93ea8SMatthew G. Knepley }
6202a5e93ea8SMatthew G. Knepley 
62039fbee547SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6204a6dfd86eSKarl Rupp {
6205552f7358SJed Brown   PetscScalar    *array;
62061b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
62071b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6208552f7358SJed Brown 
62091b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
62109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
62119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
62129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
62139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
62149566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6215b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6216b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p-1];
6217b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0     : coneO[p-1];
6218b6ebb6e6SMatthew G. Knepley 
6219b6ebb6e6SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
62209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
6221b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
6222b6ebb6e6SMatthew G. Knepley     {
6223b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6224b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
6225b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
6226b6ebb6e6SMatthew G. Knepley 
62279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
62289566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6229b6ebb6e6SMatthew G. Knepley       a    = &array[coff];
6230b6ebb6e6SMatthew G. Knepley       if (!cdof) {
6231b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6232b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6233b6ebb6e6SMatthew G. Knepley             a[k] += values[off+k];
6234b6ebb6e6SMatthew G. Knepley           }
6235b6ebb6e6SMatthew G. Knepley         } else {
6236b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6237b6ebb6e6SMatthew G. Knepley             a[k] += values[off+dof-k-1];
6238b6ebb6e6SMatthew G. Knepley           }
6239b6ebb6e6SMatthew G. Knepley         }
6240b6ebb6e6SMatthew G. Knepley       } else {
62419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6242b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6243b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6244b6ebb6e6SMatthew G. Knepley             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6245b6ebb6e6SMatthew G. Knepley             a[k] += values[off+k];
6246b6ebb6e6SMatthew G. Knepley           }
6247b6ebb6e6SMatthew G. Knepley         } else {
6248b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6249b6ebb6e6SMatthew G. Knepley             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6250b6ebb6e6SMatthew G. Knepley             a[k] += values[off+dof-k-1];
6251b6ebb6e6SMatthew G. Knepley           }
6252b6ebb6e6SMatthew G. Knepley         }
6253b6ebb6e6SMatthew G. Knepley       }
6254b6ebb6e6SMatthew G. Knepley     }
6255b6ebb6e6SMatthew G. Knepley   }
62569566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6257b6ebb6e6SMatthew G. Knepley   PetscFunctionReturn(0);
6258b6ebb6e6SMatthew G. Knepley }
62591b406b76SMatthew G. Knepley 
62601b406b76SMatthew G. Knepley /*@C
62611b406b76SMatthew G. Knepley   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
62621b406b76SMatthew G. Knepley 
62631b406b76SMatthew G. Knepley   Not collective
62641b406b76SMatthew G. Knepley 
62651b406b76SMatthew G. Knepley   Input Parameters:
62661b406b76SMatthew G. Knepley + dm - The DM
62671b406b76SMatthew G. Knepley . section - The section describing the layout in v, or NULL to use the default section
62681b406b76SMatthew G. Knepley . v - The local vector
6269eaf898f9SPatrick Sanan . point - The point in the DM
62701b406b76SMatthew G. Knepley . values - The array of values
627122c1ee49SMatthew 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,
627222c1ee49SMatthew G. Knepley          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
62731b406b76SMatthew G. Knepley 
62741b406b76SMatthew G. Knepley   Fortran Notes:
62751b406b76SMatthew G. Knepley   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
62761b406b76SMatthew G. Knepley 
62771b406b76SMatthew G. Knepley   Level: intermediate
62781b406b76SMatthew G. Knepley 
6279db781477SPatrick Sanan .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
62801b406b76SMatthew G. Knepley @*/
62811b406b76SMatthew G. Knepley PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
62821b406b76SMatthew G. Knepley {
62831b406b76SMatthew G. Knepley   PetscSection    clSection;
62841b406b76SMatthew G. Knepley   IS              clPoints;
62851b406b76SMatthew G. Knepley   PetscScalar    *array;
62861b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
628727f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
6288c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
62891b406b76SMatthew G. Knepley 
62901a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
62911b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
62929566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
62931a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
62941a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
62959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
62969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
62971b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
62989566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
62991b406b76SMatthew G. Knepley     PetscFunctionReturn(0);
63001b406b76SMatthew G. Knepley   }
63011a271a75SMatthew G. Knepley   /* Get points */
63029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6303c459fbc1SJed Brown   for (clsize=0,p=0; p<numPoints; p++) {
6304c459fbc1SJed Brown     PetscInt dof;
63059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2*p], &dof));
6306c459fbc1SJed Brown     clsize += dof;
6307c459fbc1SJed Brown   }
63089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm));
63091a271a75SMatthew G. Knepley   /* Get array */
63109566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
63111a271a75SMatthew G. Knepley   /* Get values */
6312ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
631397e99dd9SToby Isaac     PetscInt offset = 0, f;
6314552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
631597e99dd9SToby Isaac       const PetscInt    **perms = NULL;
631697e99dd9SToby Isaac       const PetscScalar **flips = NULL;
631797e99dd9SToby Isaac 
63189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6319552f7358SJed Brown       switch (mode) {
6320552f7358SJed Brown       case INSERT_VALUES:
632197e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
632297e99dd9SToby Isaac           const PetscInt    point = points[2*p];
632397e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
632497e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
632597e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6326552f7358SJed Brown         } break;
6327552f7358SJed Brown       case INSERT_ALL_VALUES:
632897e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
632997e99dd9SToby Isaac           const PetscInt    point = points[2*p];
633097e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
633197e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
633297e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6333552f7358SJed Brown         } break;
6334a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
633597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
633697e99dd9SToby Isaac           const PetscInt    point = points[2*p];
633797e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
633897e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
6339ba322698SMatthew G. Knepley           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6340a5e93ea8SMatthew G. Knepley         } break;
6341552f7358SJed Brown       case ADD_VALUES:
634297e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
634397e99dd9SToby Isaac           const PetscInt    point = points[2*p];
634497e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
634597e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
634697e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6347552f7358SJed Brown         } break;
6348552f7358SJed Brown       case ADD_ALL_VALUES:
634997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
635097e99dd9SToby Isaac           const PetscInt    point = points[2*p];
635197e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
635297e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
635397e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6354552f7358SJed Brown         } break;
6355304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
635697e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
635797e99dd9SToby Isaac           const PetscInt    point = points[2*p];
635897e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
635997e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
6360ba322698SMatthew G. Knepley           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6361304ab55fSMatthew G. Knepley         } break;
6362552f7358SJed Brown       default:
636398921bdaSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6364552f7358SJed Brown       }
63659566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
63661a271a75SMatthew G. Knepley     }
6367552f7358SJed Brown   } else {
63681a271a75SMatthew G. Knepley     PetscInt dof, off;
636997e99dd9SToby Isaac     const PetscInt    **perms = NULL;
637097e99dd9SToby Isaac     const PetscScalar **flips = NULL;
63711a271a75SMatthew G. Knepley 
63729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips));
6373552f7358SJed Brown     switch (mode) {
6374552f7358SJed Brown     case INSERT_VALUES:
637597e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
637697e99dd9SToby Isaac         const PetscInt    point = points[2*p];
637797e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
637897e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
638097e99dd9SToby Isaac         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6381552f7358SJed Brown       } break;
6382552f7358SJed Brown     case INSERT_ALL_VALUES:
638397e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
638497e99dd9SToby Isaac         const PetscInt    point = points[2*p];
638597e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
638697e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
638897e99dd9SToby Isaac         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6389552f7358SJed Brown       } break;
6390a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
639197e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
639297e99dd9SToby Isaac         const PetscInt    point = points[2*p];
639397e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
639497e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
639697e99dd9SToby Isaac         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6397a5e93ea8SMatthew G. Knepley       } break;
6398552f7358SJed Brown     case ADD_VALUES:
639997e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
640097e99dd9SToby Isaac         const PetscInt    point = points[2*p];
640197e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
640297e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
640497e99dd9SToby Isaac         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6405552f7358SJed Brown       } break;
6406552f7358SJed Brown     case ADD_ALL_VALUES:
640797e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
640897e99dd9SToby Isaac         const PetscInt    point = points[2*p];
640997e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
641097e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
641297e99dd9SToby Isaac         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6413552f7358SJed Brown       } break;
6414304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
641597e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
641697e99dd9SToby Isaac         const PetscInt    point = points[2*p];
641797e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
641897e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64199566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
642097e99dd9SToby Isaac         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6421304ab55fSMatthew G. Knepley       } break;
6422552f7358SJed Brown     default:
642398921bdaSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6424552f7358SJed Brown     }
64259566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips));
6426552f7358SJed Brown   }
64271a271a75SMatthew G. Knepley   /* Cleanup points */
64289566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
64291a271a75SMatthew G. Knepley   /* Cleanup array */
64309566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6431552f7358SJed Brown   PetscFunctionReturn(0);
6432552f7358SJed Brown }
6433552f7358SJed Brown 
64345f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
64359fbee547SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
64365f790a90SMatthew G. Knepley {
64375f790a90SMatthew G. Knepley   PetscFunctionBegin;
64385f790a90SMatthew G. Knepley   if (label) {
6439d6177c40SToby Isaac     PetscBool contains;
6440d6177c40SToby Isaac     PetscInt  fdof;
64415f790a90SMatthew G. Knepley 
6442d6177c40SToby Isaac     PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains));
6443d6177c40SToby Isaac     if (!contains) {
64449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
64455f790a90SMatthew G. Knepley       *offset += fdof;
64465f790a90SMatthew G. Knepley       PetscFunctionReturn(1);
64475f790a90SMatthew G. Knepley     }
64485f790a90SMatthew G. Knepley   }
64495f790a90SMatthew G. Knepley   PetscFunctionReturn(0);
64505f790a90SMatthew G. Knepley }
64515f790a90SMatthew G. Knepley 
645297529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
64535f790a90SMatthew G. Knepley 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)
6454e07394fbSMatthew G. Knepley {
6455e07394fbSMatthew G. Knepley   PetscSection    clSection;
6456e07394fbSMatthew G. Knepley   IS              clPoints;
6457e07394fbSMatthew G. Knepley   PetscScalar    *array;
6458e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
645997529cf3SJed Brown   const PetscInt *clp;
6460e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
646197e99dd9SToby Isaac   PetscInt        offset = 0, f;
6462e07394fbSMatthew G. Knepley 
6463e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
6464e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
64659566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6466e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6467e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
64689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6469e07394fbSMatthew G. Knepley   /* Get points */
64709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6471e07394fbSMatthew G. Knepley   /* Get array */
64729566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6473e07394fbSMatthew G. Knepley   /* Get values */
6474e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
647597e99dd9SToby Isaac     const PetscInt    **perms = NULL;
647697e99dd9SToby Isaac     const PetscScalar **flips = NULL;
647797e99dd9SToby Isaac 
6478e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
6479e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints*2; p += 2) {
6480e07394fbSMatthew G. Knepley         PetscInt fdof;
64819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6482e07394fbSMatthew G. Knepley         offset += fdof;
6483e07394fbSMatthew G. Knepley       }
6484e07394fbSMatthew G. Knepley       continue;
6485e07394fbSMatthew G. Knepley     }
64869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6487e07394fbSMatthew G. Knepley     switch (mode) {
6488e07394fbSMatthew G. Knepley     case INSERT_VALUES:
648997e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
649097e99dd9SToby Isaac         const PetscInt    point = points[2*p];
649197e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
649297e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64935f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
64949566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
6495e07394fbSMatthew G. Knepley       } break;
6496e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
649797e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
649897e99dd9SToby Isaac         const PetscInt    point = points[2*p];
649997e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
650097e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65015f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65029566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
6503e07394fbSMatthew G. Knepley       } break;
6504e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
650597e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
650697e99dd9SToby Isaac         const PetscInt    point = points[2*p];
650797e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
650897e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65095f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65109566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
6511e07394fbSMatthew G. Knepley       } break;
6512e07394fbSMatthew G. Knepley     case ADD_VALUES:
651397e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
651497e99dd9SToby Isaac         const PetscInt    point = points[2*p];
651597e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
651697e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65175f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65189566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
6519e07394fbSMatthew G. Knepley       } break;
6520e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
652197e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
652297e99dd9SToby Isaac         const PetscInt    point = points[2*p];
652397e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
652497e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65255f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65269566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
6527e07394fbSMatthew G. Knepley       } break;
6528e07394fbSMatthew G. Knepley     default:
652998921bdaSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6530e07394fbSMatthew G. Knepley     }
65319566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6532e07394fbSMatthew G. Knepley   }
6533e07394fbSMatthew G. Knepley   /* Cleanup points */
65349566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6535e07394fbSMatthew G. Knepley   /* Cleanup array */
65369566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6537e07394fbSMatthew G. Knepley   PetscFunctionReturn(0);
6538e07394fbSMatthew G. Knepley }
6539e07394fbSMatthew G. Knepley 
65407cd05799SMatthew G. Knepley static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6541552f7358SJed Brown {
6542552f7358SJed Brown   PetscMPIInt    rank;
6543552f7358SJed Brown   PetscInt       i, j;
6544552f7358SJed Brown 
6545552f7358SJed Brown   PetscFunctionBegin;
65469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
654763a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
654863a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
654963a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
6550b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
6551557cf195SMatthew G. Knepley   if (!values) PetscFunctionReturn(0);
6552b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
65539566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6554b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
6555519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
65569566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j])));
6557552f7358SJed Brown #else
65589566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]));
6559552f7358SJed Brown #endif
6560552f7358SJed Brown     }
65619566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
6562552f7358SJed Brown   }
6563552f7358SJed Brown   PetscFunctionReturn(0);
6564552f7358SJed Brown }
6565552f7358SJed Brown 
656605586334SMatthew G. Knepley /*
656705586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
656805586334SMatthew G. Knepley 
656905586334SMatthew G. Knepley   Input Parameters:
657005586334SMatthew G. Knepley + section - The section for this data layout
657136fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
657205586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
657305586334SMatthew G. Knepley . off     - The global offset of this point
657405586334SMatthew G. Knepley . loff    - The local offset of each field
6575a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
657605586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
657705586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
657805586334SMatthew G. Knepley 
657905586334SMatthew G. Knepley   Output Parameter:
658005586334SMatthew G. Knepley . indices - Indices for dofs on this point
658105586334SMatthew G. Knepley 
658205586334SMatthew G. Knepley   Level: developer
658305586334SMatthew G. Knepley 
658405586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
658505586334SMatthew G. Knepley */
658636fa2b79SJed Brown PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6587a6dfd86eSKarl Rupp {
6588e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
6589552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6590552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6591552f7358SJed Brown   PetscInt        cind = 0, k;
6592552f7358SJed Brown 
6593552f7358SJed Brown   PetscFunctionBegin;
659408401ef6SPierre Jolivet   PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
65959566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
65969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6597552f7358SJed Brown   if (!cdof || setBC) {
659805586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
659905586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
660005586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
660105586334SMatthew G. Knepley 
660205586334SMatthew G. Knepley       indices[ind] = off + k;
6603552f7358SJed Brown     }
6604552f7358SJed Brown   } else {
66059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
66064acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
660705586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
660805586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
660905586334SMatthew G. Knepley 
66104acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
66114acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
661205586334SMatthew G. Knepley         indices[ind] = -(off+k+1);
66134acb8e1eSToby Isaac         ++cind;
66144acb8e1eSToby Isaac       } else {
661536fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
6616552f7358SJed Brown       }
6617552f7358SJed Brown     }
6618552f7358SJed Brown   }
6619e6ccafaeSMatthew G Knepley   *loff += dof;
6620552f7358SJed Brown   PetscFunctionReturn(0);
6621552f7358SJed Brown }
6622552f7358SJed Brown 
66237e29afd2SMatthew G. Knepley /*
662436fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
66257e29afd2SMatthew G. Knepley 
662636fa2b79SJed Brown  Input Parameters:
662736fa2b79SJed Brown + section - a section (global or local)
662836fa2b79SJed Brown - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
662936fa2b79SJed Brown . point - point within section
663036fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
663136fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
663236fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
663336fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
663436fa2b79SJed Brown . permsoff - offset
663536fa2b79SJed Brown - indperm - index permutation
663636fa2b79SJed Brown 
663736fa2b79SJed Brown  Output Parameter:
663836fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
663936fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
664036fa2b79SJed Brown 
664136fa2b79SJed Brown  Notes:
664236fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
664336fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
664436fa2b79SJed Brown  in the local vector.
664536fa2b79SJed Brown 
664636fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
664736fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
664836fa2b79SJed Brown 
664936fa2b79SJed Brown  Developer Note:
665036fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
665136fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
665236fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
665336fa2b79SJed Brown 
665436fa2b79SJed Brown  Example:
665536fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
665636fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
665736fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
665836fa2b79SJed 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.
665936fa2b79SJed Brown 
666036fa2b79SJed Brown  Level: developer
66617e29afd2SMatthew G. Knepley */
666236fa2b79SJed Brown 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[])
6663a6dfd86eSKarl Rupp {
6664552f7358SJed Brown   PetscInt       numFields, foff, f;
6665552f7358SJed Brown 
6666552f7358SJed Brown   PetscFunctionBegin;
666708401ef6SPierre Jolivet   PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
66689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6669552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
66704acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
6671552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
66724acb8e1eSToby Isaac     PetscInt        cind = 0, b;
66734acb8e1eSToby Isaac     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6674552f7358SJed Brown 
66759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
66769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
6677552f7358SJed Brown     if (!cfdof || setBC) {
667805586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
667905586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
668005586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
668105586334SMatthew G. Knepley 
668205586334SMatthew G. Knepley         indices[ind] = off+foff+b;
668305586334SMatthew G. Knepley       }
6684552f7358SJed Brown     } else {
66859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
668605586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
668705586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
668805586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
668905586334SMatthew G. Knepley 
66904acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
669105586334SMatthew G. Knepley           indices[ind] = -(off+foff+b+1);
6692552f7358SJed Brown           ++cind;
6693552f7358SJed Brown         } else {
669436fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6695552f7358SJed Brown         }
6696552f7358SJed Brown       }
6697552f7358SJed Brown     }
669836fa2b79SJed Brown     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6699552f7358SJed Brown     foffs[f] += fdof;
6700552f7358SJed Brown   }
6701552f7358SJed Brown   PetscFunctionReturn(0);
6702552f7358SJed Brown }
6703552f7358SJed Brown 
67047e29afd2SMatthew G. Knepley /*
67057e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
67067e29afd2SMatthew G. Knepley 
67077e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
6708645102dcSJed Brown 
6709645102dcSJed Brown  Notes:
6710645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6711645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
67127e29afd2SMatthew G. Knepley */
6713645102dcSJed Brown static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
67147e29afd2SMatthew G. Knepley {
67157e29afd2SMatthew G. Knepley   PetscInt       numFields, foff, f;
67167e29afd2SMatthew G. Knepley 
67177e29afd2SMatthew G. Knepley   PetscFunctionBegin;
67189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
67197e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
67207e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
67217e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
67227e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
67237e29afd2SMatthew G. Knepley     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
67247e29afd2SMatthew G. Knepley 
67259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
67269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
67279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
6728645102dcSJed Brown     if (!cfdof) {
672905586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
673005586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
673105586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
673205586334SMatthew G. Knepley 
673305586334SMatthew G. Knepley         indices[ind] = foff+b;
673405586334SMatthew G. Knepley       }
67357e29afd2SMatthew G. Knepley     } else {
67369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
673705586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
673805586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
673905586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
674005586334SMatthew G. Knepley 
67417e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
674205586334SMatthew G. Knepley           indices[ind] = -(foff+b+1);
67437e29afd2SMatthew G. Knepley           ++cind;
67447e29afd2SMatthew G. Knepley         } else {
674505586334SMatthew G. Knepley           indices[ind] = foff+b-cind;
67467e29afd2SMatthew G. Knepley         }
67477e29afd2SMatthew G. Knepley       }
67487e29afd2SMatthew G. Knepley     }
67497e29afd2SMatthew G. Knepley     foffs[f] += fdof;
67507e29afd2SMatthew G. Knepley   }
67517e29afd2SMatthew G. Knepley   PetscFunctionReturn(0);
67527e29afd2SMatthew G. Knepley }
67537e29afd2SMatthew G. Knepley 
67544acb8e1eSToby Isaac 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)
6755d3d1a6afSToby Isaac {
6756d3d1a6afSToby Isaac   Mat             cMat;
6757d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
6758d3d1a6afSToby Isaac   IS              aIS;
6759d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
6760d3d1a6afSToby Isaac   const PetscInt  *anchors;
6761e17c06e0SMatthew G. Knepley   PetscInt        numFields, f, p, q, newP = 0;
6762d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
6763d3d1a6afSToby Isaac   PetscInt        *newPoints, *indices, *newIndices;
6764d3d1a6afSToby Isaac   PetscInt        maxAnchor, maxDof;
6765d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
6766d3d1a6afSToby Isaac   PetscInt        *pointMatOffsets[32];
6767d3d1a6afSToby Isaac   PetscInt        *newPointOffsets[32];
6768d3d1a6afSToby Isaac   PetscScalar     *pointMat[32];
67696ecaa68aSToby Isaac   PetscScalar     *newValues=NULL,*tmpValues;
6770d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
6771d3d1a6afSToby Isaac 
6772d3d1a6afSToby Isaac   PetscFunctionBegin;
6773d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6774d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
67759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6776d3d1a6afSToby Isaac 
67779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS));
6778d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
6779d3d1a6afSToby Isaac   if (aSec) {
67809566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
67819566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS,&anchors));
67829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd));
6783d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
6784d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
6785d3d1a6afSToby Isaac      * into the global matrix anyway) */
6786d3d1a6afSToby Isaac     for (p = 0; p < 2*numPoints; p+=2) {
6787d3d1a6afSToby Isaac       PetscInt b    = points[p];
67884b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6789d3d1a6afSToby Isaac 
67909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,b,&bSecDof));
67914b2f2278SToby Isaac       if (!bSecDof) {
67924b2f2278SToby Isaac         continue;
67934b2f2278SToby Isaac       }
6794d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
67959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,b,&bDof));
6796d3d1a6afSToby Isaac       }
6797d3d1a6afSToby Isaac       if (bDof) {
6798d3d1a6afSToby Isaac         /* this point is constrained */
6799d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
6800d3d1a6afSToby Isaac         PetscInt bOff, q;
6801d3d1a6afSToby Isaac 
6802d3d1a6afSToby Isaac         anyConstrained = PETSC_TRUE;
6803d3d1a6afSToby Isaac         newNumPoints  += bDof;
68049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,b,&bOff));
6805d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
6806d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q];
6807d3d1a6afSToby Isaac           PetscInt aDof;
6808d3d1a6afSToby Isaac 
68099566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,a,&aDof));
6810d3d1a6afSToby Isaac           newNumIndices += aDof;
6811d3d1a6afSToby Isaac           for (f = 0; f < numFields; ++f) {
6812d3d1a6afSToby Isaac             PetscInt fDof;
6813d3d1a6afSToby Isaac 
68149566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
6815d3d1a6afSToby Isaac             newOffsets[f+1] += fDof;
6816d3d1a6afSToby Isaac           }
6817d3d1a6afSToby Isaac         }
6818d3d1a6afSToby Isaac       }
6819d3d1a6afSToby Isaac       else {
6820d3d1a6afSToby Isaac         /* this point is not constrained */
6821d3d1a6afSToby Isaac         newNumPoints++;
68224b2f2278SToby Isaac         newNumIndices += bSecDof;
6823d3d1a6afSToby Isaac         for (f = 0; f < numFields; ++f) {
6824d3d1a6afSToby Isaac           PetscInt fDof;
6825d3d1a6afSToby Isaac 
68269566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
6827d3d1a6afSToby Isaac           newOffsets[f+1] += fDof;
6828d3d1a6afSToby Isaac         }
6829d3d1a6afSToby Isaac       }
6830d3d1a6afSToby Isaac     }
6831d3d1a6afSToby Isaac   }
6832d3d1a6afSToby Isaac   if (!anyConstrained) {
683372b80496SMatthew G. Knepley     if (outNumPoints)  *outNumPoints  = 0;
683472b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
683572b80496SMatthew G. Knepley     if (outPoints)     *outPoints     = NULL;
683672b80496SMatthew G. Knepley     if (outValues)     *outValues     = NULL;
68379566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors));
6838d3d1a6afSToby Isaac     PetscFunctionReturn(0);
6839d3d1a6afSToby Isaac   }
6840d3d1a6afSToby Isaac 
68416ecaa68aSToby Isaac   if (outNumPoints)  *outNumPoints  = newNumPoints;
68426ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
68436ecaa68aSToby Isaac 
6844f13f9184SToby Isaac   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6845d3d1a6afSToby Isaac 
68466ecaa68aSToby Isaac   if (!outPoints && !outValues) {
68476ecaa68aSToby Isaac     if (offsets) {
68486ecaa68aSToby Isaac       for (f = 0; f <= numFields; f++) {
68496ecaa68aSToby Isaac         offsets[f] = newOffsets[f];
68506ecaa68aSToby Isaac       }
68516ecaa68aSToby Isaac     }
68529566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors));
68536ecaa68aSToby Isaac     PetscFunctionReturn(0);
68546ecaa68aSToby Isaac   }
68556ecaa68aSToby Isaac 
68561dca8a05SBarry 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);
6857d3d1a6afSToby Isaac 
68589566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
6859d3d1a6afSToby Isaac 
6860d3d1a6afSToby Isaac   /* workspaces */
6861d3d1a6afSToby Isaac   if (numFields) {
6862d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
68639566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]));
68649566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]));
6865d3d1a6afSToby Isaac     }
6866d3d1a6afSToby Isaac   }
6867d3d1a6afSToby Isaac   else {
68689566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]));
68699566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]));
6870d3d1a6afSToby Isaac   }
6871d3d1a6afSToby Isaac 
6872d3d1a6afSToby Isaac   /* get workspaces for the point-to-point matrices */
6873d3d1a6afSToby Isaac   if (numFields) {
68744b2f2278SToby Isaac     PetscInt totalOffset, totalMatOffset;
68754b2f2278SToby Isaac 
6876d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
6877d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
68784b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6879d3d1a6afSToby Isaac 
68809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,b,&bSecDof));
68814b2f2278SToby Isaac       if (!bSecDof) {
68824b2f2278SToby Isaac         for (f = 0; f < numFields; f++) {
68834b2f2278SToby Isaac           newPointOffsets[f][p + 1] = 0;
68844b2f2278SToby Isaac           pointMatOffsets[f][p + 1] = 0;
68854b2f2278SToby Isaac         }
68864b2f2278SToby Isaac         continue;
68874b2f2278SToby Isaac       }
6888d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
68899566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
6890d3d1a6afSToby Isaac       }
6891d3d1a6afSToby Isaac       if (bDof) {
6892d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
6893d3d1a6afSToby Isaac           PetscInt fDof, q, bOff, allFDof = 0;
6894d3d1a6afSToby Isaac 
68959566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
68969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
6897d3d1a6afSToby Isaac           for (q = 0; q < bDof; q++) {
6898d3d1a6afSToby Isaac             PetscInt a = anchors[bOff + q];
6899d3d1a6afSToby Isaac             PetscInt aFDof;
6900d3d1a6afSToby Isaac 
69019566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
6902d3d1a6afSToby Isaac             allFDof += aFDof;
6903d3d1a6afSToby Isaac           }
6904d3d1a6afSToby Isaac           newPointOffsets[f][p+1] = allFDof;
6905d3d1a6afSToby Isaac           pointMatOffsets[f][p+1] = fDof * allFDof;
6906d3d1a6afSToby Isaac         }
6907d3d1a6afSToby Isaac       }
6908d3d1a6afSToby Isaac       else {
6909d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
6910d3d1a6afSToby Isaac           PetscInt fDof;
6911d3d1a6afSToby Isaac 
69129566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
6913d3d1a6afSToby Isaac           newPointOffsets[f][p+1] = fDof;
6914d3d1a6afSToby Isaac           pointMatOffsets[f][p+1] = 0;
6915d3d1a6afSToby Isaac         }
6916d3d1a6afSToby Isaac       }
6917d3d1a6afSToby Isaac     }
69184b2f2278SToby Isaac     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
69194b2f2278SToby Isaac       newPointOffsets[f][0] = totalOffset;
69204b2f2278SToby Isaac       pointMatOffsets[f][0] = totalMatOffset;
6921d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
6922d3d1a6afSToby Isaac         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6923d3d1a6afSToby Isaac         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6924d3d1a6afSToby Isaac       }
692519f70fd5SToby Isaac       totalOffset    = newPointOffsets[f][numPoints];
692619f70fd5SToby Isaac       totalMatOffset = pointMatOffsets[f][numPoints];
69279566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]));
6928d3d1a6afSToby Isaac     }
6929d3d1a6afSToby Isaac   }
6930d3d1a6afSToby Isaac   else {
6931d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
6932d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
69334b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6934d3d1a6afSToby Isaac 
69359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,b,&bSecDof));
69364b2f2278SToby Isaac       if (!bSecDof) {
69374b2f2278SToby Isaac         newPointOffsets[0][p + 1] = 0;
69384b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = 0;
69394b2f2278SToby Isaac         continue;
69404b2f2278SToby Isaac       }
6941d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
69429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
6943d3d1a6afSToby Isaac       }
6944d3d1a6afSToby Isaac       if (bDof) {
69454b2f2278SToby Isaac         PetscInt bOff, q, allDof = 0;
6946d3d1a6afSToby Isaac 
69479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
6948d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
6949d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aDof;
6950d3d1a6afSToby Isaac 
69519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
6952d3d1a6afSToby Isaac           allDof += aDof;
6953d3d1a6afSToby Isaac         }
6954d3d1a6afSToby Isaac         newPointOffsets[0][p+1] = allDof;
69554b2f2278SToby Isaac         pointMatOffsets[0][p+1] = bSecDof * allDof;
6956d3d1a6afSToby Isaac       }
6957d3d1a6afSToby Isaac       else {
69584b2f2278SToby Isaac         newPointOffsets[0][p+1] = bSecDof;
6959d3d1a6afSToby Isaac         pointMatOffsets[0][p+1] = 0;
6960d3d1a6afSToby Isaac       }
6961d3d1a6afSToby Isaac     }
6962d3d1a6afSToby Isaac     newPointOffsets[0][0] = 0;
6963d3d1a6afSToby Isaac     pointMatOffsets[0][0] = 0;
6964d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
6965d3d1a6afSToby Isaac       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6966d3d1a6afSToby Isaac       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6967d3d1a6afSToby Isaac     }
69689566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]));
6969d3d1a6afSToby Isaac   }
6970d3d1a6afSToby Isaac 
69716ecaa68aSToby Isaac   /* output arrays */
69729566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints));
69736ecaa68aSToby Isaac 
6974d3d1a6afSToby Isaac   /* get the point-to-point matrices; construct newPoints */
69759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
69769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
69779566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices));
69789566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices));
6979d3d1a6afSToby Isaac   if (numFields) {
6980d3d1a6afSToby Isaac     for (p = 0, newP = 0; p < numPoints; p++) {
6981d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
6982d3d1a6afSToby Isaac       PetscInt o    = points[2*p+1];
69834b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6984d3d1a6afSToby Isaac 
69859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
69864b2f2278SToby Isaac       if (!bSecDof) {
69874b2f2278SToby Isaac         continue;
69884b2f2278SToby Isaac       }
6989d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
69909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
6991d3d1a6afSToby Isaac       }
6992d3d1a6afSToby Isaac       if (bDof) {
6993d3d1a6afSToby Isaac         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6994d3d1a6afSToby Isaac 
6995d3d1a6afSToby Isaac         fStart[0] = 0;
6996d3d1a6afSToby Isaac         fEnd[0]   = 0;
6997d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
6998d3d1a6afSToby Isaac           PetscInt fDof;
6999d3d1a6afSToby Isaac 
70009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7001d3d1a6afSToby Isaac           fStart[f+1] = fStart[f] + fDof;
7002d3d1a6afSToby Isaac           fEnd[f+1]   = fStart[f+1];
7003d3d1a6afSToby Isaac         }
70049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
70059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
7006d3d1a6afSToby Isaac 
7007d3d1a6afSToby Isaac         fAnchorStart[0] = 0;
7008d3d1a6afSToby Isaac         fAnchorEnd[0]   = 0;
7009d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7010d3d1a6afSToby Isaac           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7011d3d1a6afSToby Isaac 
7012d3d1a6afSToby Isaac           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
7013d3d1a6afSToby Isaac           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
7014d3d1a6afSToby Isaac         }
70159566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7016d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7017d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7018d3d1a6afSToby Isaac 
7019d3d1a6afSToby 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 */
7020d3d1a6afSToby Isaac           newPoints[2*(newP + q)]     = a;
7021d3d1a6afSToby Isaac           newPoints[2*(newP + q) + 1] = 0;
70229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
70239566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7024d3d1a6afSToby Isaac         }
7025d3d1a6afSToby Isaac         newP += bDof;
7026d3d1a6afSToby Isaac 
70276ecaa68aSToby Isaac         if (outValues) {
7028d3d1a6afSToby Isaac           /* get the point-to-point submatrix */
7029d3d1a6afSToby Isaac           for (f = 0; f < numFields; f++) {
70309566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]));
7031d3d1a6afSToby Isaac           }
7032d3d1a6afSToby Isaac         }
70336ecaa68aSToby Isaac       }
7034d3d1a6afSToby Isaac       else {
7035d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7036d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7037d3d1a6afSToby Isaac         newP++;
7038d3d1a6afSToby Isaac       }
7039d3d1a6afSToby Isaac     }
7040d3d1a6afSToby Isaac   } else {
7041d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7042d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
7043d3d1a6afSToby Isaac       PetscInt o    = points[2*p+1];
70444b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7045d3d1a6afSToby Isaac 
70469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
70474b2f2278SToby Isaac       if (!bSecDof) {
70484b2f2278SToby Isaac         continue;
70494b2f2278SToby Isaac       }
7050d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
70519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7052d3d1a6afSToby Isaac       }
7053d3d1a6afSToby Isaac       if (bDof) {
7054d3d1a6afSToby Isaac         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7055d3d1a6afSToby Isaac 
70569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
70579566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7058d3d1a6afSToby Isaac 
70599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset (aSec, b, &bOff));
7060d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7061d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7062d3d1a6afSToby Isaac 
7063d3d1a6afSToby 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 */
7064d3d1a6afSToby Isaac 
7065d3d1a6afSToby Isaac           newPoints[2*(newP + q)]     = a;
7066d3d1a6afSToby Isaac           newPoints[2*(newP + q) + 1] = 0;
70679566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
70689566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7069d3d1a6afSToby Isaac         }
7070d3d1a6afSToby Isaac         newP += bDof;
7071d3d1a6afSToby Isaac 
7072d3d1a6afSToby Isaac         /* get the point-to-point submatrix */
70736ecaa68aSToby Isaac         if (outValues) {
70749566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]));
7075d3d1a6afSToby Isaac         }
70766ecaa68aSToby Isaac       }
7077d3d1a6afSToby Isaac       else {
7078d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7079d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7080d3d1a6afSToby Isaac         newP++;
7081d3d1a6afSToby Isaac       }
7082d3d1a6afSToby Isaac     }
7083d3d1a6afSToby Isaac   }
7084d3d1a6afSToby Isaac 
70856ecaa68aSToby Isaac   if (outValues) {
70869566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues));
70879566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices));
7088d3d1a6afSToby Isaac     /* multiply constraints on the right */
7089d3d1a6afSToby Isaac     if (numFields) {
7090d3d1a6afSToby Isaac       for (f = 0; f < numFields; f++) {
7091d3d1a6afSToby Isaac         PetscInt oldOff = offsets[f];
7092d3d1a6afSToby Isaac 
7093d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7094d3d1a6afSToby Isaac           PetscInt cStart = newPointOffsets[f][p];
7095d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7096d3d1a6afSToby Isaac           PetscInt c, r, k;
7097d3d1a6afSToby Isaac           PetscInt dof;
7098d3d1a6afSToby Isaac 
70999566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,b,f,&dof));
71004b2f2278SToby Isaac           if (!dof) {
71014b2f2278SToby Isaac             continue;
71024b2f2278SToby Isaac           }
7103d3d1a6afSToby Isaac           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7104d3d1a6afSToby Isaac             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7105d3d1a6afSToby Isaac             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7106d3d1a6afSToby Isaac 
7107d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7108d3d1a6afSToby Isaac               for (c = 0; c < nCols; c++) {
7109d3d1a6afSToby Isaac                 for (k = 0; k < dof; k++) {
71104acb8e1eSToby Isaac                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7111d3d1a6afSToby Isaac                 }
7112d3d1a6afSToby Isaac               }
7113d3d1a6afSToby Isaac             }
7114d3d1a6afSToby Isaac           }
7115d3d1a6afSToby Isaac           else {
7116d3d1a6afSToby Isaac             /* copy this column as is */
7117d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7118d3d1a6afSToby Isaac               for (c = 0; c < dof; c++) {
7119d3d1a6afSToby Isaac                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7120d3d1a6afSToby Isaac               }
7121d3d1a6afSToby Isaac             }
7122d3d1a6afSToby Isaac           }
7123d3d1a6afSToby Isaac           oldOff += dof;
7124d3d1a6afSToby Isaac         }
7125d3d1a6afSToby Isaac       }
7126d3d1a6afSToby Isaac     }
7127d3d1a6afSToby Isaac     else {
7128d3d1a6afSToby Isaac       PetscInt oldOff = 0;
7129d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7130d3d1a6afSToby Isaac         PetscInt cStart = newPointOffsets[0][p];
7131d3d1a6afSToby Isaac         PetscInt b      = points[2 * p];
7132d3d1a6afSToby Isaac         PetscInt c, r, k;
7133d3d1a6afSToby Isaac         PetscInt dof;
7134d3d1a6afSToby Isaac 
71359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section,b,&dof));
71364b2f2278SToby Isaac         if (!dof) {
71374b2f2278SToby Isaac           continue;
71384b2f2278SToby Isaac         }
7139d3d1a6afSToby Isaac         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7140d3d1a6afSToby Isaac           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7141d3d1a6afSToby Isaac           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7142d3d1a6afSToby Isaac 
7143d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7144d3d1a6afSToby Isaac             for (c = 0; c < nCols; c++) {
7145d3d1a6afSToby Isaac               for (k = 0; k < dof; k++) {
7146d3d1a6afSToby Isaac                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7147d3d1a6afSToby Isaac               }
7148d3d1a6afSToby Isaac             }
7149d3d1a6afSToby Isaac           }
7150d3d1a6afSToby Isaac         }
7151d3d1a6afSToby Isaac         else {
7152d3d1a6afSToby Isaac           /* copy this column as is */
7153d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7154d3d1a6afSToby Isaac             for (c = 0; c < dof; c++) {
7155d3d1a6afSToby Isaac               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7156d3d1a6afSToby Isaac             }
7157d3d1a6afSToby Isaac           }
7158d3d1a6afSToby Isaac         }
7159d3d1a6afSToby Isaac         oldOff += dof;
7160d3d1a6afSToby Isaac       }
7161d3d1a6afSToby Isaac     }
7162d3d1a6afSToby Isaac 
71636ecaa68aSToby Isaac     if (multiplyLeft) {
71649566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues));
71659566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices));
7166d3d1a6afSToby Isaac       /* multiply constraints transpose on the left */
7167d3d1a6afSToby Isaac       if (numFields) {
7168d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7169d3d1a6afSToby Isaac           PetscInt oldOff = offsets[f];
7170d3d1a6afSToby Isaac 
7171d3d1a6afSToby Isaac           for (p = 0; p < numPoints; p++) {
7172d3d1a6afSToby Isaac             PetscInt rStart = newPointOffsets[f][p];
7173d3d1a6afSToby Isaac             PetscInt b      = points[2 * p];
7174d3d1a6afSToby Isaac             PetscInt c, r, k;
7175d3d1a6afSToby Isaac             PetscInt dof;
7176d3d1a6afSToby Isaac 
71779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,b,f,&dof));
7178d3d1a6afSToby Isaac             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7179d3d1a6afSToby Isaac               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7180d3d1a6afSToby Isaac               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7181d3d1a6afSToby Isaac 
7182d3d1a6afSToby Isaac               for (r = 0; r < nRows; r++) {
7183d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7184d3d1a6afSToby Isaac                   for (k = 0; k < dof; k++) {
7185d3d1a6afSToby Isaac                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7186d3d1a6afSToby Isaac                   }
7187d3d1a6afSToby Isaac                 }
7188d3d1a6afSToby Isaac               }
7189d3d1a6afSToby Isaac             }
7190d3d1a6afSToby Isaac             else {
7191d3d1a6afSToby Isaac               /* copy this row as is */
7192d3d1a6afSToby Isaac               for (r = 0; r < dof; r++) {
7193d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7194d3d1a6afSToby Isaac                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7195d3d1a6afSToby Isaac                 }
7196d3d1a6afSToby Isaac               }
7197d3d1a6afSToby Isaac             }
7198d3d1a6afSToby Isaac             oldOff += dof;
7199d3d1a6afSToby Isaac           }
7200d3d1a6afSToby Isaac         }
7201d3d1a6afSToby Isaac       }
7202d3d1a6afSToby Isaac       else {
7203d3d1a6afSToby Isaac         PetscInt oldOff = 0;
7204d3d1a6afSToby Isaac 
7205d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7206d3d1a6afSToby Isaac           PetscInt rStart = newPointOffsets[0][p];
7207d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7208d3d1a6afSToby Isaac           PetscInt c, r, k;
7209d3d1a6afSToby Isaac           PetscInt dof;
7210d3d1a6afSToby Isaac 
72119566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,b,&dof));
7212d3d1a6afSToby Isaac           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7213d3d1a6afSToby Isaac             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7214d3d1a6afSToby Isaac             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7215d3d1a6afSToby Isaac 
7216d3d1a6afSToby Isaac             for (r = 0; r < nRows; r++) {
7217d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7218d3d1a6afSToby Isaac                 for (k = 0; k < dof; k++) {
7219d3d1a6afSToby Isaac                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7220d3d1a6afSToby Isaac                 }
7221d3d1a6afSToby Isaac               }
7222d3d1a6afSToby Isaac             }
7223d3d1a6afSToby Isaac           }
7224d3d1a6afSToby Isaac           else {
7225d3d1a6afSToby Isaac             /* copy this row as is */
72269fc93327SToby Isaac             for (r = 0; r < dof; r++) {
7227d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7228d3d1a6afSToby Isaac                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7229d3d1a6afSToby Isaac               }
7230d3d1a6afSToby Isaac             }
7231d3d1a6afSToby Isaac           }
7232d3d1a6afSToby Isaac           oldOff += dof;
7233d3d1a6afSToby Isaac         }
7234d3d1a6afSToby Isaac       }
7235d3d1a6afSToby Isaac 
72369566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues));
72376ecaa68aSToby Isaac     }
72386ecaa68aSToby Isaac     else {
72396ecaa68aSToby Isaac       newValues = tmpValues;
72406ecaa68aSToby Isaac     }
72416ecaa68aSToby Isaac   }
72426ecaa68aSToby Isaac 
7243d3d1a6afSToby Isaac   /* clean up */
72449566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices));
72459566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices));
72466ecaa68aSToby Isaac 
7247d3d1a6afSToby Isaac   if (numFields) {
7248d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
72499566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]));
72509566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]));
72519566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]));
7252d3d1a6afSToby Isaac     }
7253d3d1a6afSToby Isaac   }
7254d3d1a6afSToby Isaac   else {
72559566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]));
72569566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]));
72579566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]));
7258d3d1a6afSToby Isaac   }
72599566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
7260d3d1a6afSToby Isaac 
7261d3d1a6afSToby Isaac   /* output */
72626ecaa68aSToby Isaac   if (outPoints) {
7263d3d1a6afSToby Isaac     *outPoints = newPoints;
72646ecaa68aSToby Isaac   }
72656ecaa68aSToby Isaac   else {
72669566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints));
72676ecaa68aSToby Isaac   }
726831620726SToby Isaac   if (outValues) {
7269d3d1a6afSToby Isaac     *outValues = newValues;
72706ecaa68aSToby Isaac   }
72716ecaa68aSToby Isaac   for (f = 0; f <= numFields; f++) {
7272d3d1a6afSToby Isaac     offsets[f] = newOffsets[f];
7273d3d1a6afSToby Isaac   }
7274d3d1a6afSToby Isaac   PetscFunctionReturn(0);
7275d3d1a6afSToby Isaac }
7276d3d1a6afSToby Isaac 
72774a1e0b3eSMatthew G. Knepley /*@C
727871f0bbf9SMatthew G. Knepley   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
72797cd05799SMatthew G. Knepley 
72807cd05799SMatthew G. Knepley   Not collective
72817cd05799SMatthew G. Knepley 
72827cd05799SMatthew G. Knepley   Input Parameters:
72837cd05799SMatthew G. Knepley + dm         - The DM
728471f0bbf9SMatthew G. Knepley . section    - The PetscSection describing the points (a local section)
728571f0bbf9SMatthew G. Knepley . idxSection - The PetscSection from which to obtain indices (may be local or global)
728671f0bbf9SMatthew G. Knepley . point      - The point defining the closure
728771f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
72887cd05799SMatthew G. Knepley 
728971f0bbf9SMatthew G. Knepley   Output Parameters:
729071f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
729171f0bbf9SMatthew G. Knepley . indices    - The dof indices
729271f0bbf9SMatthew G. Knepley . outOffsets - Array to write the field offsets into, or NULL
729371f0bbf9SMatthew G. Knepley - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
72947cd05799SMatthew G. Knepley 
729536fa2b79SJed Brown   Notes:
729636fa2b79SJed Brown   Must call DMPlexRestoreClosureIndices() to free allocated memory
729736fa2b79SJed Brown 
729836fa2b79SJed Brown   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
729936fa2b79SJed Brown   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
730036fa2b79SJed Brown   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
730136fa2b79SJed Brown   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
730236fa2b79SJed Brown   indices (with the above semantics) are implied.
73037cd05799SMatthew G. Knepley 
73047cd05799SMatthew G. Knepley   Level: advanced
73057cd05799SMatthew G. Knepley 
7306db781477SPatrick Sanan .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
73074a1e0b3eSMatthew G. Knepley @*/
730871f0bbf9SMatthew G. Knepley PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
730971f0bbf9SMatthew G. Knepley                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
73107773e69fSMatthew G. Knepley {
731171f0bbf9SMatthew G. Knepley   /* Closure ordering */
73127773e69fSMatthew G. Knepley   PetscSection        clSection;
73137773e69fSMatthew G. Knepley   IS                  clPoints;
731471f0bbf9SMatthew G. Knepley   const PetscInt     *clp;
731571f0bbf9SMatthew G. Knepley   PetscInt           *points;
731671f0bbf9SMatthew G. Knepley   const PetscInt     *clperm = NULL;
731771f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
73184acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
731971f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
732071f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
732171f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
732271f0bbf9SMatthew G. Knepley   PetscInt           *pointsC = NULL;
732371f0bbf9SMatthew G. Knepley   PetscScalar        *valuesC = NULL;
732471f0bbf9SMatthew G. Knepley   PetscInt            NclC, NiC;
732571f0bbf9SMatthew G. Knepley 
732671f0bbf9SMatthew G. Knepley   PetscInt           *idx;
732771f0bbf9SMatthew G. Knepley   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
732871f0bbf9SMatthew G. Knepley   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
73297773e69fSMatthew G. Knepley 
733071f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
73317773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
73327773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
733336fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7334dadcf809SJacob Faibussowitsch   if (numIndices) PetscValidIntPointer(numIndices, 6);
733571f0bbf9SMatthew G. Knepley   if (indices)    PetscValidPointer(indices, 7);
7336dadcf809SJacob Faibussowitsch   if (outOffsets) PetscValidIntPointer(outOffsets, 8);
733771f0bbf9SMatthew G. Knepley   if (values)     PetscValidPointer(values, 9);
73389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
733963a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
73409566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
734171f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
73429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7343c459fbc1SJed Brown   if (useClPerm) {
7344c459fbc1SJed Brown     PetscInt depth, clsize;
73459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7346c459fbc1SJed Brown     for (clsize=0,p=0; p<Ncl; p++) {
7347c459fbc1SJed Brown       PetscInt dof;
73489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2*p], &dof));
7349c459fbc1SJed Brown       clsize += dof;
7350c459fbc1SJed Brown     }
73519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm));
7352c459fbc1SJed Brown   }
735371f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
735471f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl*2; p += 2) {
73557773e69fSMatthew G. Knepley     PetscInt dof, fdof;
73567773e69fSMatthew G. Knepley 
73579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
73587773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
73599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
73607773e69fSMatthew G. Knepley       offsets[f+1] += fdof;
73617773e69fSMatthew G. Knepley     }
736271f0bbf9SMatthew G. Knepley     Ni += dof;
73637773e69fSMatthew G. Knepley   }
73647773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
73651dca8a05SBarry 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);
736671f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
736771f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
73689566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
73699566063dSJacob Faibussowitsch     else    PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
737071f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
737171f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
737271f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
73736ecaa68aSToby Isaac 
737471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
737571f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2*p], fdof;
737671f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
737771f0bbf9SMatthew G. Knepley 
73789566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
73799566063dSJacob Faibussowitsch         else     PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
738071f0bbf9SMatthew G. Knepley         if (flip) {
738171f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
738271f0bbf9SMatthew G. Knepley 
738371f0bbf9SMatthew G. Knepley           if (!valCopy) {
73849566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy));
738571f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
738671f0bbf9SMatthew G. Knepley             *values = valCopy;
738771f0bbf9SMatthew G. Knepley           }
738871f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
738971f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
739071f0bbf9SMatthew G. Knepley 
739171f0bbf9SMatthew G. Knepley             for (k = 0; k < Ni; ++k) {
739271f0bbf9SMatthew G. Knepley               valCopy[Ni * (foffset + i) + k] *= fval;
739371f0bbf9SMatthew G. Knepley               valCopy[Ni * k + (foffset + i)] *= fval;
73946ecaa68aSToby Isaac             }
73956ecaa68aSToby Isaac           }
739671f0bbf9SMatthew G. Knepley         }
739771f0bbf9SMatthew G. Knepley         foffset += fdof;
739871f0bbf9SMatthew G. Knepley       }
739971f0bbf9SMatthew G. Knepley     }
740071f0bbf9SMatthew G. Knepley   }
740171f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
74029566063dSJacob Faibussowitsch   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
740371f0bbf9SMatthew G. Knepley   if (NclC) {
74049566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy));
740571f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
74069566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
74079566063dSJacob Faibussowitsch       else    PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
740871f0bbf9SMatthew G. Knepley     }
740971f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
74109566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
74119566063dSJacob Faibussowitsch       else    PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
741271f0bbf9SMatthew G. Knepley     }
74139566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
741471f0bbf9SMatthew G. Knepley     Ncl     = NclC;
741571f0bbf9SMatthew G. Knepley     Ni      = NiC;
741671f0bbf9SMatthew G. Knepley     points  = pointsC;
741771f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
741871f0bbf9SMatthew G. Knepley   }
741971f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
74209566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
742171f0bbf9SMatthew G. Knepley   if (Nf) {
742271f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
742371f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
742471f0bbf9SMatthew G. Knepley 
742571f0bbf9SMatthew G. Knepley     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
74269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
742771f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
742871f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
742971f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p*2];
743071f0bbf9SMatthew G. Knepley 
74319566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
74327773e69fSMatthew G. Knepley       }
74337773e69fSMatthew G. Knepley     } else {
743471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
743571f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p*2];
743671f0bbf9SMatthew G. Knepley 
74379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
743871f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
743971f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
744071f0bbf9SMatthew G. Knepley          * global section. */
74419566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
744271f0bbf9SMatthew G. Knepley       }
744371f0bbf9SMatthew G. Knepley     }
744471f0bbf9SMatthew G. Knepley   } else {
744571f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
744671f0bbf9SMatthew G. Knepley 
744771f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
744871f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p*2];
74494acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
74504acb8e1eSToby Isaac 
74519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
745271f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
745371f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
74549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
74557773e69fSMatthew G. Knepley     }
74567773e69fSMatthew G. Knepley   }
745771f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
745871f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
74599566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
74609566063dSJacob Faibussowitsch     else    PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
74614acb8e1eSToby Isaac   }
746271f0bbf9SMatthew G. Knepley   if (NclC) {
74639566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC));
74647773e69fSMatthew G. Knepley   } else {
74659566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
74667773e69fSMatthew G. Knepley   }
746771f0bbf9SMatthew G. Knepley 
746871f0bbf9SMatthew G. Knepley   if (numIndices) *numIndices = Ni;
746971f0bbf9SMatthew G. Knepley   if (indices)    *indices    = idx;
74707773e69fSMatthew G. Knepley   PetscFunctionReturn(0);
74717773e69fSMatthew G. Knepley }
74727773e69fSMatthew G. Knepley 
74737cd05799SMatthew G. Knepley /*@C
747471f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
74757cd05799SMatthew G. Knepley 
74767cd05799SMatthew G. Knepley   Not collective
74777cd05799SMatthew G. Knepley 
74787cd05799SMatthew G. Knepley   Input Parameters:
74797cd05799SMatthew G. Knepley + dm         - The DM
748071f0bbf9SMatthew G. Knepley . section    - The PetscSection describing the points (a local section)
748171f0bbf9SMatthew G. Knepley . idxSection - The PetscSection from which to obtain indices (may be local or global)
748271f0bbf9SMatthew G. Knepley . point      - The point defining the closure
748371f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
748471f0bbf9SMatthew G. Knepley 
748571f0bbf9SMatthew G. Knepley   Output Parameters:
748671f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
748771f0bbf9SMatthew G. Knepley . indices    - The dof indices
748871f0bbf9SMatthew G. Knepley . outOffsets - Array to write the field offsets into, or NULL
748971f0bbf9SMatthew G. Knepley - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
749071f0bbf9SMatthew G. Knepley 
749171f0bbf9SMatthew G. Knepley   Notes:
749271f0bbf9SMatthew G. Knepley   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
749371f0bbf9SMatthew G. Knepley 
749471f0bbf9SMatthew G. Knepley   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
749571f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
749671f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
749771f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
749871f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
74997cd05799SMatthew G. Knepley 
75007cd05799SMatthew G. Knepley   Level: advanced
75017cd05799SMatthew G. Knepley 
7502db781477SPatrick Sanan .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
75037cd05799SMatthew G. Knepley @*/
750471f0bbf9SMatthew G. Knepley PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
750571f0bbf9SMatthew G. Knepley                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
75067773e69fSMatthew G. Knepley {
75077773e69fSMatthew G. Knepley   PetscFunctionBegin;
75087773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7509064a246eSJacob Faibussowitsch   PetscValidPointer(indices, 7);
75109566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
75117773e69fSMatthew G. Knepley   PetscFunctionReturn(0);
75127773e69fSMatthew G. Knepley }
75137773e69fSMatthew G. Knepley 
75147f5d1fdeSMatthew G. Knepley /*@C
75157f5d1fdeSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
75167f5d1fdeSMatthew G. Knepley 
75177f5d1fdeSMatthew G. Knepley   Not collective
75187f5d1fdeSMatthew G. Knepley 
75197f5d1fdeSMatthew G. Knepley   Input Parameters:
75207f5d1fdeSMatthew G. Knepley + dm - The DM
7521ebd6d717SJed Brown . section - The section describing the layout in v, or NULL to use the default section
7522ebd6d717SJed Brown . globalSection - The section describing the layout in v, or NULL to use the default global section
75237f5d1fdeSMatthew G. Knepley . A - The matrix
7524eaf898f9SPatrick Sanan . point - The point in the DM
75257f5d1fdeSMatthew G. Knepley . values - The array of values
75267f5d1fdeSMatthew G. Knepley - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
75277f5d1fdeSMatthew G. Knepley 
75287f5d1fdeSMatthew G. Knepley   Fortran Notes:
75297f5d1fdeSMatthew G. Knepley   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
75307f5d1fdeSMatthew G. Knepley 
75317f5d1fdeSMatthew G. Knepley   Level: intermediate
75327f5d1fdeSMatthew G. Knepley 
7533db781477SPatrick Sanan .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
75347f5d1fdeSMatthew G. Knepley @*/
75357c1f9639SMatthew G Knepley PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7536552f7358SJed Brown {
7537552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex*) dm->data;
7538552f7358SJed Brown   PetscInt          *indices;
753971f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
754071f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
7541552f7358SJed Brown   PetscErrorCode     ierr;
7542552f7358SJed Brown 
7543552f7358SJed Brown   PetscFunctionBegin;
7544552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
75459566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
75463dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
75479566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
75483dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
75493dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7550552f7358SJed Brown 
75519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
75520d644c17SKarl Rupp 
75539566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7554d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
75554a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7556552f7358SJed Brown   if (ierr) {
7557552f7358SJed Brown     PetscMPIInt    rank;
7558552f7358SJed Brown 
75599566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
75609566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
75619566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
75629566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
75639566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7564c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values");
7565552f7358SJed Brown   }
75664a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
75674a1e0b3eSMatthew G. Knepley     PetscInt i;
75689566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
756963a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
75709566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
75714a1e0b3eSMatthew G. Knepley   }
757271f0bbf9SMatthew G. Knepley 
75739566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
75749566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
757571f0bbf9SMatthew G. Knepley   PetscFunctionReturn(0);
75764acb8e1eSToby Isaac }
757771f0bbf9SMatthew G. Knepley 
75784a1e0b3eSMatthew G. Knepley /*@C
75794a1e0b3eSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
75804a1e0b3eSMatthew G. Knepley 
75814a1e0b3eSMatthew G. Knepley   Not collective
75824a1e0b3eSMatthew G. Knepley 
75834a1e0b3eSMatthew G. Knepley   Input Parameters:
75844a1e0b3eSMatthew G. Knepley + dmRow - The DM for the row fields
75854a1e0b3eSMatthew G. Knepley . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
75864a1e0b3eSMatthew G. Knepley . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
75874a1e0b3eSMatthew G. Knepley . dmCol - The DM for the column fields
75884a1e0b3eSMatthew G. Knepley . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
75894a1e0b3eSMatthew G. Knepley . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
75904a1e0b3eSMatthew G. Knepley . A - The matrix
75914a1e0b3eSMatthew G. Knepley . point - The point in the DMs
75924a1e0b3eSMatthew G. Knepley . values - The array of values
75934a1e0b3eSMatthew G. Knepley - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
75944a1e0b3eSMatthew G. Knepley 
75954a1e0b3eSMatthew G. Knepley   Level: intermediate
75964a1e0b3eSMatthew G. Knepley 
7597db781477SPatrick Sanan .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
75984a1e0b3eSMatthew G. Knepley @*/
759971f0bbf9SMatthew G. Knepley PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
760071f0bbf9SMatthew G. Knepley {
760171f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
760271f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
760371f0bbf9SMatthew G. Knepley   PetscInt           numIndicesRow, numIndicesCol;
760471f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
760571f0bbf9SMatthew G. Knepley   PetscErrorCode     ierr;
760671f0bbf9SMatthew G. Knepley 
760771f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
760871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
76099566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
761071f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
76119566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
761271f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
761371f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
76149566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
761571f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
76169566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
761771f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
761871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
761971f0bbf9SMatthew G. Knepley 
76209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
76219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values));
762271f0bbf9SMatthew G. Knepley 
76239566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7624d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
76254a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
762671f0bbf9SMatthew G. Knepley   if (ierr) {
762771f0bbf9SMatthew G. Knepley     PetscMPIInt    rank;
762871f0bbf9SMatthew G. Knepley 
76299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
76309566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
76319566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
76329566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
76339566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values));
76349566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7635d3d1a6afSToby Isaac   }
763671f0bbf9SMatthew G. Knepley 
76379566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
76389566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values));
76399566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7640552f7358SJed Brown   PetscFunctionReturn(0);
7641552f7358SJed Brown }
7642552f7358SJed Brown 
7643de41b84cSMatthew G. Knepley PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7644de41b84cSMatthew G. Knepley {
7645de41b84cSMatthew G. Knepley   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7646de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7647de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
7648de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
764917c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7650de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
7651412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
76524ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7653de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
7654de41b84cSMatthew G. Knepley 
7655de41b84cSMatthew G. Knepley   PetscFunctionBegin;
7656de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7657de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
76589566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
7659de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
76609566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
7661de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
76629566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
7663de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
76649566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
7665de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7666de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
76679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
766863a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
76699566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
76709566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
7671de41b84cSMatthew G. Knepley   /* Column indices */
76729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
76734ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
7674de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
7675de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
76769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
7677de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7678de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7679de41b84cSMatthew G. Knepley       cpoints[q*2]   = cpoints[p];
7680de41b84cSMatthew G. Knepley       cpoints[q*2+1] = cpoints[p+1];
7681de41b84cSMatthew G. Knepley       ++q;
7682de41b84cSMatthew G. Knepley     }
7683de41b84cSMatthew G. Knepley   }
7684de41b84cSMatthew G. Knepley   numCPoints = q;
7685de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7686de41b84cSMatthew G. Knepley     PetscInt fdof;
7687de41b84cSMatthew G. Knepley 
76889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
76894ca5e9f5SMatthew G. Knepley     if (!dof) continue;
7690de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
76919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
7692de41b84cSMatthew G. Knepley       coffsets[f+1] += fdof;
7693de41b84cSMatthew G. Knepley     }
7694de41b84cSMatthew G. Knepley     numCIndices += dof;
7695de41b84cSMatthew G. Knepley   }
7696de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7697de41b84cSMatthew G. Knepley   /* Row indices */
76989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
7699412e9a14SMatthew G. Knepley   {
7700012bc364SMatthew G. Knepley     DMPlexTransform tr;
7701012bc364SMatthew G. Knepley     DMPolytopeType *rct;
7702012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
7703012bc364SMatthew G. Knepley 
77049566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
77059566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
77069566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7707012bc364SMatthew G. Knepley     numSubcells = rsize[Nt-1];
77089566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
7709412e9a14SMatthew G. Knepley   }
77109566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints));
7711de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
7712de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
77139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
7714de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
77159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
7716de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints*2; p += 2) {
7717de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
77189566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
77194ca5e9f5SMatthew G. Knepley         if (!dof) continue;
77204ca5e9f5SMatthew G. Knepley         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
77214ca5e9f5SMatthew G. Knepley         if (s < q) continue;
7722de41b84cSMatthew G. Knepley         ftotpoints[q*2]   = fpoints[p];
7723de41b84cSMatthew G. Knepley         ftotpoints[q*2+1] = fpoints[p+1];
7724de41b84cSMatthew G. Knepley         ++q;
7725de41b84cSMatthew G. Knepley       }
7726de41b84cSMatthew G. Knepley     }
77279566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
7728de41b84cSMatthew G. Knepley   }
7729de41b84cSMatthew G. Knepley   numFPoints = q;
7730de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7731de41b84cSMatthew G. Knepley     PetscInt fdof;
7732de41b84cSMatthew G. Knepley 
77339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
77344ca5e9f5SMatthew G. Knepley     if (!dof) continue;
7735de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
77369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
7737de41b84cSMatthew G. Knepley       foffsets[f+1] += fdof;
7738de41b84cSMatthew G. Knepley     }
7739de41b84cSMatthew G. Knepley     numFIndices += dof;
7740de41b84cSMatthew G. Knepley   }
7741de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7742de41b84cSMatthew G. Knepley 
77431dca8a05SBarry 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);
77441dca8a05SBarry 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);
77459566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
77469566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7747de41b84cSMatthew G. Knepley   if (numFields) {
77484acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
77494acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
77504acb8e1eSToby Isaac 
77514acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
77529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
77539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7754de41b84cSMatthew G. Knepley     }
77554acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
77569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
77579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
77584acb8e1eSToby Isaac     }
77594acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
77609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
77619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
77624acb8e1eSToby Isaac     }
77634acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
77649566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
77659566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7766de41b84cSMatthew G. Knepley     }
7767de41b84cSMatthew G. Knepley   } else {
77684acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
77694acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
77704acb8e1eSToby Isaac 
77719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
77729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL));
77734acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
77744acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
77754acb8e1eSToby Isaac 
77769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
77779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
7778de41b84cSMatthew G. Knepley     }
77794acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
77804acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
77814acb8e1eSToby Isaac 
77829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
77839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
7784de41b84cSMatthew G. Knepley     }
77859566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
77869566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL));
7787de41b84cSMatthew G. Knepley   }
77889566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
77894acb8e1eSToby Isaac   /* TODO: flips */
7790d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
7791de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7792de41b84cSMatthew G. Knepley   if (ierr) {
7793de41b84cSMatthew G. Knepley     PetscMPIInt    rank;
7794de41b84cSMatthew G. Knepley 
77959566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
77969566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
77979566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
77989566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
77999566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7800de41b84cSMatthew G. Knepley   }
78019566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints));
78029566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
78039566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
78049566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7805de41b84cSMatthew G. Knepley   PetscFunctionReturn(0);
7806de41b84cSMatthew G. Knepley }
7807de41b84cSMatthew G. Knepley 
78087c927364SMatthew G. Knepley PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
78097c927364SMatthew G. Knepley {
78107c927364SMatthew G. Knepley   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
78117c927364SMatthew G. Knepley   PetscInt      *cpoints = NULL;
78127c927364SMatthew G. Knepley   PetscInt       foffsets[32], coffsets[32];
781317c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7814412e9a14SMatthew G. Knepley   DMPolytopeType ct;
78157c927364SMatthew G. Knepley   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
78167c927364SMatthew G. Knepley 
78177c927364SMatthew G. Knepley   PetscFunctionBegin;
78187c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
78197c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
78209566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
78217c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
78229566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
78237c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
78249566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
78257c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
78269566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
78277c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
78289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
782963a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
78309566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
78319566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
78327c927364SMatthew G. Knepley   /* Column indices */
78339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
78347c927364SMatthew G. Knepley   maxFPoints = numCPoints;
78357c927364SMatthew G. Knepley   /* Compress out points not in the section */
78367c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
78379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
78387c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
78397c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
78407c927364SMatthew G. Knepley       cpoints[q*2]   = cpoints[p];
78417c927364SMatthew G. Knepley       cpoints[q*2+1] = cpoints[p+1];
78427c927364SMatthew G. Knepley       ++q;
78437c927364SMatthew G. Knepley     }
78447c927364SMatthew G. Knepley   }
78457c927364SMatthew G. Knepley   numCPoints = q;
78467c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
78477c927364SMatthew G. Knepley     PetscInt fdof;
78487c927364SMatthew G. Knepley 
78499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
78507c927364SMatthew G. Knepley     if (!dof) continue;
78517c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
78529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
78537c927364SMatthew G. Knepley       coffsets[f+1] += fdof;
78547c927364SMatthew G. Knepley     }
78557c927364SMatthew G. Knepley     numCIndices += dof;
78567c927364SMatthew G. Knepley   }
78577c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
78587c927364SMatthew G. Knepley   /* Row indices */
78599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
7860412e9a14SMatthew G. Knepley   {
7861012bc364SMatthew G. Knepley     DMPlexTransform tr;
7862012bc364SMatthew G. Knepley     DMPolytopeType *rct;
7863012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
7864012bc364SMatthew G. Knepley 
78659566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
78669566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
78679566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7868012bc364SMatthew G. Knepley     numSubcells = rsize[Nt-1];
78699566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
7870412e9a14SMatthew G. Knepley   }
78719566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints));
78727c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
78737c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
78749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
78757c927364SMatthew G. Knepley     /* Compress out points not in the section */
78769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
78777c927364SMatthew G. Knepley     for (p = 0; p < numFPoints*2; p += 2) {
78787c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
78799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
78807c927364SMatthew G. Knepley         if (!dof) continue;
78817c927364SMatthew G. Knepley         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
78827c927364SMatthew G. Knepley         if (s < q) continue;
78837c927364SMatthew G. Knepley         ftotpoints[q*2]   = fpoints[p];
78847c927364SMatthew G. Knepley         ftotpoints[q*2+1] = fpoints[p+1];
78857c927364SMatthew G. Knepley         ++q;
78867c927364SMatthew G. Knepley       }
78877c927364SMatthew G. Knepley     }
78889566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
78897c927364SMatthew G. Knepley   }
78907c927364SMatthew G. Knepley   numFPoints = q;
78917c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
78927c927364SMatthew G. Knepley     PetscInt fdof;
78937c927364SMatthew G. Knepley 
78949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
78957c927364SMatthew G. Knepley     if (!dof) continue;
78967c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
78979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
78987c927364SMatthew G. Knepley       foffsets[f+1] += fdof;
78997c927364SMatthew G. Knepley     }
79007c927364SMatthew G. Knepley     numFIndices += dof;
79017c927364SMatthew G. Knepley   }
79027c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
79037c927364SMatthew G. Knepley 
79041dca8a05SBarry 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);
79051dca8a05SBarry 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);
79067c927364SMatthew G. Knepley   if (numFields) {
79074acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
79084acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
79094acb8e1eSToby Isaac 
79104acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
79119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
79129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
79137c927364SMatthew G. Knepley     }
79144acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
79159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
79169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
79174acb8e1eSToby Isaac     }
79184acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
79199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
79209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
79214acb8e1eSToby Isaac     }
79224acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
79239566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
79249566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
79257c927364SMatthew G. Knepley     }
79267c927364SMatthew G. Knepley   } else {
79274acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
79284acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
79294acb8e1eSToby Isaac 
79309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
79319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL));
79324acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
79334acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
79344acb8e1eSToby Isaac 
79359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
79369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
79377c927364SMatthew G. Knepley     }
79384acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
79394acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
79404acb8e1eSToby Isaac 
79419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
79429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
79437c927364SMatthew G. Knepley     }
79449566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
79459566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL));
79467c927364SMatthew G. Knepley   }
79479566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints));
79489566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
79497c927364SMatthew G. Knepley   PetscFunctionReturn(0);
79507c927364SMatthew G. Knepley }
79517c927364SMatthew G. Knepley 
79527cd05799SMatthew G. Knepley /*@C
79537cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
79547cd05799SMatthew G. Knepley 
79557cd05799SMatthew G. Knepley   Input Parameter:
79567cd05799SMatthew G. Knepley . dm   - The DMPlex object
79577cd05799SMatthew G. Knepley 
79587cd05799SMatthew G. Knepley   Output Parameter:
79597cd05799SMatthew G. Knepley . cellHeight - The height of a cell
79607cd05799SMatthew G. Knepley 
79617cd05799SMatthew G. Knepley   Level: developer
79627cd05799SMatthew G. Knepley 
7963db781477SPatrick Sanan .seealso `DMPlexSetVTKCellHeight()`
79647cd05799SMatthew G. Knepley @*/
7965552f7358SJed Brown PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7966552f7358SJed Brown {
7967552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
7968552f7358SJed Brown 
7969552f7358SJed Brown   PetscFunctionBegin;
7970552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7971dadcf809SJacob Faibussowitsch   PetscValidIntPointer(cellHeight, 2);
7972552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
7973552f7358SJed Brown   PetscFunctionReturn(0);
7974552f7358SJed Brown }
7975552f7358SJed Brown 
79767cd05799SMatthew G. Knepley /*@C
79777cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
79787cd05799SMatthew G. Knepley 
79797cd05799SMatthew G. Knepley   Input Parameters:
79807cd05799SMatthew G. Knepley + dm   - The DMPlex object
79817cd05799SMatthew G. Knepley - cellHeight - The height of a cell
79827cd05799SMatthew G. Knepley 
79837cd05799SMatthew G. Knepley   Level: developer
79847cd05799SMatthew G. Knepley 
7985db781477SPatrick Sanan .seealso `DMPlexGetVTKCellHeight()`
79867cd05799SMatthew G. Knepley @*/
7987552f7358SJed Brown PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7988552f7358SJed Brown {
7989552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
7990552f7358SJed Brown 
7991552f7358SJed Brown   PetscFunctionBegin;
7992552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7993552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
7994552f7358SJed Brown   PetscFunctionReturn(0);
7995552f7358SJed Brown }
7996552f7358SJed Brown 
7997e6139122SMatthew G. Knepley /*@
7998e6139122SMatthew G. Knepley   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7999e6139122SMatthew G. Knepley 
8000e6139122SMatthew G. Knepley   Input Parameter:
8001e6139122SMatthew G. Knepley . dm - The DMPlex object
8002e6139122SMatthew G. Knepley 
8003e6139122SMatthew G. Knepley   Output Parameters:
80042a9f31c0SMatthew G. Knepley + gcStart - The first ghost cell, or NULL
80052a9f31c0SMatthew G. Knepley - gcEnd   - The upper bound on ghost cells, or NULL
8006e6139122SMatthew G. Knepley 
80072a9f31c0SMatthew G. Knepley   Level: advanced
8008e6139122SMatthew G. Knepley 
8009db781477SPatrick Sanan .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()`
8010e6139122SMatthew G. Knepley @*/
8011e6139122SMatthew G. Knepley PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
8012e6139122SMatthew G. Knepley {
8013412e9a14SMatthew G. Knepley   DMLabel        ctLabel;
8014e6139122SMatthew G. Knepley 
8015e6139122SMatthew G. Knepley   PetscFunctionBegin;
8016e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
80189566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd));
8019e6139122SMatthew G. Knepley   PetscFunctionReturn(0);
8020e6139122SMatthew G. Knepley }
8021e6139122SMatthew G. Knepley 
80229886b8cfSStefano Zampini PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8023552f7358SJed Brown {
8024552f7358SJed Brown   PetscSection   section, globalSection;
8025552f7358SJed Brown   PetscInt      *numbers, p;
8026552f7358SJed Brown 
8027552f7358SJed Brown   PetscFunctionBegin;
80286c1ef331SVaclav Hapla   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf));
80299566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
80309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8031552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
80329566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section, p, 1));
8033552f7358SJed Brown   }
80349566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
80359566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
80369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8037552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
80389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]));
8039ef48cebcSMatthew G. Knepley     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
8040ef48cebcSMatthew G. Knepley     else                       numbers[p-pStart] += shift;
8041552f7358SJed Brown   }
80429566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8043ef48cebcSMatthew G. Knepley   if (globalSize) {
8044ef48cebcSMatthew G. Knepley     PetscLayout layout;
80459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout));
80469566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
80479566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8048ef48cebcSMatthew G. Knepley   }
80499566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
80509566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
8051552f7358SJed Brown   PetscFunctionReturn(0);
8052552f7358SJed Brown }
8053552f7358SJed Brown 
805481ed3555SMatthew G. Knepley PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8055552f7358SJed Brown {
8056412e9a14SMatthew G. Knepley   PetscInt       cellHeight, cStart, cEnd;
8057552f7358SJed Brown 
8058552f7358SJed Brown   PetscFunctionBegin;
80599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
80609566063dSJacob Faibussowitsch   if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
80619566063dSJacob Faibussowitsch   else               PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
80629566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
806381ed3555SMatthew G. Knepley   PetscFunctionReturn(0);
8064552f7358SJed Brown }
806581ed3555SMatthew G. Knepley 
80668dab3259SMatthew G. Knepley /*@
80677cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
80687cd05799SMatthew G. Knepley 
80697cd05799SMatthew G. Knepley   Input Parameter:
80707cd05799SMatthew G. Knepley . dm   - The DMPlex object
80717cd05799SMatthew G. Knepley 
80727cd05799SMatthew G. Knepley   Output Parameter:
80737cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
80747cd05799SMatthew G. Knepley 
80757cd05799SMatthew G. Knepley   Level: developer
80767cd05799SMatthew G. Knepley 
8077db781477SPatrick Sanan .seealso `DMPlexGetVertexNumbering()`
80787cd05799SMatthew G. Knepley @*/
807981ed3555SMatthew G. Knepley PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
808081ed3555SMatthew G. Knepley {
808181ed3555SMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
808281ed3555SMatthew G. Knepley 
808381ed3555SMatthew G. Knepley   PetscFunctionBegin;
808481ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80859566063dSJacob Faibussowitsch   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8086552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
8087552f7358SJed Brown   PetscFunctionReturn(0);
8088552f7358SJed Brown }
8089552f7358SJed Brown 
809081ed3555SMatthew G. Knepley PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
809181ed3555SMatthew G. Knepley {
8092412e9a14SMatthew G. Knepley   PetscInt       vStart, vEnd;
809381ed3555SMatthew G. Knepley 
809481ed3555SMatthew G. Knepley   PetscFunctionBegin;
809581ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
80979566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
809881ed3555SMatthew G. Knepley   PetscFunctionReturn(0);
809981ed3555SMatthew G. Knepley }
810081ed3555SMatthew G. Knepley 
81018dab3259SMatthew G. Knepley /*@
81026aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
81037cd05799SMatthew G. Knepley 
81047cd05799SMatthew G. Knepley   Input Parameter:
81057cd05799SMatthew G. Knepley . dm   - The DMPlex object
81067cd05799SMatthew G. Knepley 
81077cd05799SMatthew G. Knepley   Output Parameter:
81087cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
81097cd05799SMatthew G. Knepley 
81107cd05799SMatthew G. Knepley   Level: developer
81117cd05799SMatthew G. Knepley 
8112db781477SPatrick Sanan .seealso `DMPlexGetCellNumbering()`
81137cd05799SMatthew G. Knepley @*/
8114552f7358SJed Brown PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8115552f7358SJed Brown {
8116552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
8117552f7358SJed Brown 
8118552f7358SJed Brown   PetscFunctionBegin;
8119552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81209566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8121552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
8122552f7358SJed Brown   PetscFunctionReturn(0);
8123552f7358SJed Brown }
8124552f7358SJed Brown 
81258dab3259SMatthew G. Knepley /*@
81267cd05799SMatthew G. Knepley   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
81277cd05799SMatthew G. Knepley 
81287cd05799SMatthew G. Knepley   Input Parameter:
81297cd05799SMatthew G. Knepley . dm   - The DMPlex object
81307cd05799SMatthew G. Knepley 
81317cd05799SMatthew G. Knepley   Output Parameter:
81327cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
81337cd05799SMatthew G. Knepley 
81347cd05799SMatthew G. Knepley   Level: developer
81357cd05799SMatthew G. Knepley 
8136db781477SPatrick Sanan .seealso `DMPlexGetCellNumbering()`
81377cd05799SMatthew G. Knepley @*/
8138ef48cebcSMatthew G. Knepley PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8139ef48cebcSMatthew G. Knepley {
8140ef48cebcSMatthew G. Knepley   IS             nums[4];
8141862913ffSStefano Zampini   PetscInt       depths[4], gdepths[4], starts[4];
8142ef48cebcSMatthew G. Knepley   PetscInt       depth, d, shift = 0;
8143ef48cebcSMatthew G. Knepley 
8144ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8145ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
81478abc87a0SMichael Lange   /* For unstratified meshes use dim instead of depth */
81489566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
8149862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8150862913ffSStefano Zampini     PetscInt end;
8151862913ffSStefano Zampini 
8152862913ffSStefano Zampini     depths[d] = depth-d;
81539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
8154862913ffSStefano Zampini     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8155862913ffSStefano Zampini   }
81569566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(depth+1, starts, depths));
81571c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm)));
8158862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
81591dca8a05SBarry Smith     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]);
8160862913ffSStefano Zampini   }
8161ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8162ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8163ef48cebcSMatthew G. Knepley 
81649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
81659566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8166ef48cebcSMatthew G. Knepley     shift += gsize;
8167ef48cebcSMatthew G. Knepley   }
81689566063dSJacob Faibussowitsch   PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers));
81699566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
8170ef48cebcSMatthew G. Knepley   PetscFunctionReturn(0);
8171ef48cebcSMatthew G. Knepley }
8172ef48cebcSMatthew G. Knepley 
817308a22f4bSMatthew G. Knepley /*@
817408a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
817508a22f4bSMatthew G. Knepley 
817608a22f4bSMatthew G. Knepley   Input Parameter:
817708a22f4bSMatthew G. Knepley . dm - The DMPlex object
817808a22f4bSMatthew G. Knepley 
817908a22f4bSMatthew G. Knepley   Output Parameter:
818008a22f4bSMatthew G. Knepley . ranks - The rank field
818108a22f4bSMatthew G. Knepley 
818208a22f4bSMatthew G. Knepley   Options Database Keys:
818308a22f4bSMatthew G. Knepley . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
818408a22f4bSMatthew G. Knepley 
818508a22f4bSMatthew G. Knepley   Level: intermediate
818608a22f4bSMatthew G. Knepley 
8187db781477SPatrick Sanan .seealso: `DMView()`
818808a22f4bSMatthew G. Knepley @*/
818908a22f4bSMatthew G. Knepley PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
819008a22f4bSMatthew G. Knepley {
819108a22f4bSMatthew G. Knepley   DM             rdm;
819208a22f4bSMatthew G. Knepley   PetscFE        fe;
819308a22f4bSMatthew G. Knepley   PetscScalar   *r;
819408a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
8195a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
819608a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
8197a55f9a55SMatthew G. Knepley   PetscBool      simplex;
819808a22f4bSMatthew G. Knepley 
819908a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
8200f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8201f95ace6aSMatthew G. Knepley   PetscValidPointer(ranks, 2);
82029566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
82039566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
82049566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
82059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
82069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8207a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
82089566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
82099566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) fe, "rank"));
82109566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe));
82119566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
82129566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
82139566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
82149566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition"));
82159566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
821608a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
821708a22f4bSMatthew G. Knepley     PetscScalar *lr;
821808a22f4bSMatthew G. Knepley 
82199566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
822071f09efeSPierre Jolivet     if (lr) *lr = rank;
822108a22f4bSMatthew G. Knepley   }
82229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
82239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
822408a22f4bSMatthew G. Knepley   PetscFunctionReturn(0);
822508a22f4bSMatthew G. Knepley }
822608a22f4bSMatthew G. Knepley 
8227ca8062c8SMatthew G. Knepley /*@
822818e14f0cSMatthew G. Knepley   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
822918e14f0cSMatthew G. Knepley 
823018e14f0cSMatthew G. Knepley   Input Parameters:
823118e14f0cSMatthew G. Knepley + dm    - The DMPlex
823218e14f0cSMatthew G. Knepley - label - The DMLabel
823318e14f0cSMatthew G. Knepley 
823418e14f0cSMatthew G. Knepley   Output Parameter:
823518e14f0cSMatthew G. Knepley . val - The label value field
823618e14f0cSMatthew G. Knepley 
823718e14f0cSMatthew G. Knepley   Options Database Keys:
823818e14f0cSMatthew G. Knepley . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
823918e14f0cSMatthew G. Knepley 
824018e14f0cSMatthew G. Knepley   Level: intermediate
824118e14f0cSMatthew G. Knepley 
8242db781477SPatrick Sanan .seealso: `DMView()`
824318e14f0cSMatthew G. Knepley @*/
824418e14f0cSMatthew G. Knepley PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
824518e14f0cSMatthew G. Knepley {
824618e14f0cSMatthew G. Knepley   DM             rdm;
824718e14f0cSMatthew G. Knepley   PetscFE        fe;
824818e14f0cSMatthew G. Knepley   PetscScalar   *v;
824918e14f0cSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
825018e14f0cSMatthew G. Knepley 
825118e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
825218e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
825318e14f0cSMatthew G. Knepley   PetscValidPointer(label, 2);
825418e14f0cSMatthew G. Knepley   PetscValidPointer(val, 3);
82559566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
82569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
82579566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
82589566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) fe, "label_value"));
82599566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe));
82609566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
82619566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
82629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
82639566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
82649566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *val, "label_value"));
82659566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*val, &v));
826618e14f0cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
826718e14f0cSMatthew G. Knepley     PetscScalar *lv;
826818e14f0cSMatthew G. Knepley     PetscInt     cval;
826918e14f0cSMatthew G. Knepley 
82709566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv));
82719566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, c, &cval));
827218e14f0cSMatthew G. Knepley     *lv = cval;
827318e14f0cSMatthew G. Knepley   }
82749566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*val, &v));
82759566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
827618e14f0cSMatthew G. Knepley   PetscFunctionReturn(0);
827718e14f0cSMatthew G. Knepley }
827818e14f0cSMatthew G. Knepley 
827918e14f0cSMatthew G. Knepley /*@
8280ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8281ca8062c8SMatthew G. Knepley 
828269916449SMatthew G. Knepley   Input Parameter:
828369916449SMatthew G. Knepley . dm - The DMPlex object
8284ca8062c8SMatthew G. Knepley 
828595eb5ee5SVaclav Hapla   Notes:
828695eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
828795eb5ee5SVaclav Hapla 
828895eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8289ca8062c8SMatthew G. Knepley 
8290ca8062c8SMatthew G. Knepley   Level: developer
8291ca8062c8SMatthew G. Knepley 
8292db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8293ca8062c8SMatthew G. Knepley @*/
8294ca8062c8SMatthew G. Knepley PetscErrorCode DMPlexCheckSymmetry(DM dm)
8295ca8062c8SMatthew G. Knepley {
8296ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
8297ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
8298ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
829957beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
830057beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
8301ca8062c8SMatthew G. Knepley 
8302ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8303ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
83049566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
83059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
83069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
8307ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
83089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8309ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
83109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
83119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
8312ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
831342e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
831442e66dfaSMatthew G. Knepley       PetscInt  d;
831542e66dfaSMatthew G. Knepley       for (d = c-1; d >= 0; --d) {
831642e66dfaSMatthew G. Knepley         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
831742e66dfaSMatthew G. Knepley       }
83189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
83199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
8320ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
8321ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
8322ca8062c8SMatthew G. Knepley       }
832342e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
832463a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
8325ca8062c8SMatthew G. Knepley         for (s = 0; s < coneSize; ++s) {
832663a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
8327ca8062c8SMatthew G. Knepley         }
83289566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
832963a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
8330ca8062c8SMatthew G. Knepley         for (s = 0; s < supportSize; ++s) {
833163a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
8332ca8062c8SMatthew G. Knepley         }
83339566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
833463a3b9bcSJacob 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]);
8335f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
8336ca8062c8SMatthew G. Knepley       }
833742e66dfaSMatthew G. Knepley     }
83389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
833957beb4faSStefano Zampini     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
83409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
83419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
8342ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
83439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
83449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
8345ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
83469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
834757beb4faSStefano Zampini         if (cone[c] != pp) { c = 0; break; }
8348ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
8349ca8062c8SMatthew G. Knepley       }
8350ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
835163a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
8352ca8062c8SMatthew G. Knepley         for (c = 0; c < supportSize; ++c) {
835363a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
8354ca8062c8SMatthew G. Knepley         }
83559566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
835663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
8357ca8062c8SMatthew G. Knepley         for (c = 0; c < coneSize; ++c) {
835863a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
8359ca8062c8SMatthew G. Knepley         }
83609566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
836163a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
8362ca8062c8SMatthew G. Knepley       }
8363ca8062c8SMatthew G. Knepley     }
8364ca8062c8SMatthew G. Knepley   }
836557beb4faSStefano Zampini   if (storagecheck) {
83669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
83679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
836863a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
836957beb4faSStefano Zampini   }
8370ca8062c8SMatthew G. Knepley   PetscFunctionReturn(0);
8371ca8062c8SMatthew G. Knepley }
8372ca8062c8SMatthew G. Knepley 
8373412e9a14SMatthew G. Knepley /*
8374412e9a14SMatthew 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.
8375412e9a14SMatthew G. Knepley */
8376412e9a14SMatthew G. Knepley static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8377412e9a14SMatthew G. Knepley {
8378412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
8379412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
8380412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
8381412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8382412e9a14SMatthew G. Knepley 
8383412e9a14SMatthew G. Knepley   PetscFunctionBegin;
8384412e9a14SMatthew G. Knepley   *unsplit = 0;
8385412e9a14SMatthew G. Knepley   switch (ct) {
8386b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8387b5a892a1SMatthew G. Knepley       ptpoints[npt++] = c;
8388b5a892a1SMatthew G. Knepley       break;
8389412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
83909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
83919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8392412e9a14SMatthew G. Knepley       for (cp = 0; cp < coneSize; ++cp) {
83939566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
8394412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8395412e9a14SMatthew G. Knepley       }
8396412e9a14SMatthew G. Knepley       break;
8397412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8398412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
83999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
84009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8401412e9a14SMatthew G. Knepley       for (cp = 0; cp < coneSize; ++cp) {
84029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
84039566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
8404412e9a14SMatthew G. Knepley         for (ccp = 0; ccp < cconeSize; ++ccp) {
84059566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
8406412e9a14SMatthew G. Knepley           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8407412e9a14SMatthew G. Knepley             PetscInt p;
8408412e9a14SMatthew G. Knepley             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8409412e9a14SMatthew G. Knepley             if (p == npt) ptpoints[npt++] = ccone[ccp];
8410412e9a14SMatthew G. Knepley           }
8411412e9a14SMatthew G. Knepley         }
8412412e9a14SMatthew G. Knepley       }
8413412e9a14SMatthew G. Knepley       break;
8414412e9a14SMatthew G. Knepley     default: break;
8415412e9a14SMatthew G. Knepley   }
8416412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
84179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
8418412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8419412e9a14SMatthew G. Knepley   }
8420412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
8421412e9a14SMatthew G. Knepley }
8422412e9a14SMatthew G. Knepley 
8423ca8062c8SMatthew G. Knepley /*@
8424ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8425ca8062c8SMatthew G. Knepley 
8426ca8062c8SMatthew G. Knepley   Input Parameters:
8427ca8062c8SMatthew G. Knepley + dm - The DMPlex object
842858723a97SMatthew G. Knepley - cellHeight - Normally 0
8429ca8062c8SMatthew G. Knepley 
843095eb5ee5SVaclav Hapla   Notes:
843195eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
843225c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
8433ca8062c8SMatthew G. Knepley 
843495eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
843595eb5ee5SVaclav Hapla 
8436ca8062c8SMatthew G. Knepley   Level: developer
8437ca8062c8SMatthew G. Knepley 
8438db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8439ca8062c8SMatthew G. Knepley @*/
844025c50c26SVaclav Hapla PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8441ca8062c8SMatthew G. Knepley {
8442412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
8443412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
8444412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
8445ca8062c8SMatthew G. Knepley 
8446ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8447ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84489566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
84499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
84509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8451412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8452412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
8453412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
845458723a97SMatthew G. Knepley 
84559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
845663a3b9bcSJacob Faibussowitsch     PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c);
8457412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8458412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
84599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
846063a3b9bcSJacob 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));
8461412e9a14SMatthew G. Knepley     }
84629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
846358723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
846458723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
8465412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
846658723a97SMatthew G. Knepley     }
84679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8468412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
8469412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8470412e9a14SMatthew G. Knepley       PetscInt unsplit;
847142363296SMatthew G. Knepley 
84729566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8473412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
847442363296SMatthew G. Knepley     }
847563a3b9bcSJacob 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));
847642363296SMatthew G. Knepley   }
8477ca8062c8SMatthew G. Knepley   PetscFunctionReturn(0);
8478ca8062c8SMatthew G. Knepley }
84799bf0dad6SMatthew G. Knepley 
84809bf0dad6SMatthew G. Knepley /*@
84819bf0dad6SMatthew 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
84829bf0dad6SMatthew G. Knepley 
84838f6815adSVaclav Hapla   Collective
8484899ea2b8SJacob Faibussowitsch 
84859bf0dad6SMatthew G. Knepley   Input Parameters:
84869bf0dad6SMatthew G. Knepley + dm - The DMPlex object
84879bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
84889bf0dad6SMatthew G. Knepley 
848945da879fSVaclav Hapla   Notes:
849045da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
849145da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
849245da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
849345da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
84949bf0dad6SMatthew G. Knepley 
849595eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
849695eb5ee5SVaclav Hapla 
84979bf0dad6SMatthew G. Knepley   Level: developer
84989bf0dad6SMatthew G. Knepley 
8499db781477SPatrick Sanan .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
85009bf0dad6SMatthew G. Knepley @*/
850125c50c26SVaclav Hapla PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
85029bf0dad6SMatthew G. Knepley {
8503ab91121cSMatthew G. Knepley   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8504899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
85059bf0dad6SMatthew G. Knepley 
85069bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
85079bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
85088f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
850945da879fSVaclav Hapla   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
85108f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
85118f6815adSVaclav Hapla     PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported");
85128f6815adSVaclav Hapla     PetscFunctionReturn(0);
8513899ea2b8SJacob Faibussowitsch   }
8514899ea2b8SJacob Faibussowitsch 
85159566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
85169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
85179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8518ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
85199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
85203554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
8521412e9a14SMatthew G. Knepley       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8522412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
8523ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
8524412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
8525412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
85269bf0dad6SMatthew G. Knepley 
85279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
85289566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8529412e9a14SMatthew G. Knepley       if (unsplit) continue;
85309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
85319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
85329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
85339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
85349bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize*2; cl += 2) {
85359bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
85369bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
85379bf0dad6SMatthew G. Knepley       }
85389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
853963a3b9bcSJacob 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);
85409bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
8541d4961f80SStefano Zampini         DMPolytopeType fct;
85429bf0dad6SMatthew G. Knepley         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
85439bf0dad6SMatthew G. Knepley 
85449566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
85459566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
85469bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize*2; cl += 2) {
85479bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
85489bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
85499bf0dad6SMatthew G. Knepley         }
855063a3b9bcSJacob 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]);
85519bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
8552b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff+v]) {
8553b5a892a1SMatthew G. Knepley             PetscInt v1;
8554b5a892a1SMatthew G. Knepley 
85559566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
855663a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
85579566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
855863a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1]));
85599566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
856063a3b9bcSJacob 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]);
8561b5a892a1SMatthew G. Knepley           }
85629bf0dad6SMatthew G. Knepley         }
85639566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
8564412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
85659bf0dad6SMatthew G. Knepley       }
85669566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
85679566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
85689bf0dad6SMatthew G. Knepley     }
85693554e41dSMatthew G. Knepley   }
8570552f7358SJed Brown   PetscFunctionReturn(0);
8571552f7358SJed Brown }
85723913d7c8SMatthew G. Knepley 
8573bb6a34a8SMatthew G. Knepley /*@
8574bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
8575bb6a34a8SMatthew G. Knepley 
8576bb6a34a8SMatthew G. Knepley   Input Parameter:
8577bb6a34a8SMatthew G. Knepley . dm - The DMPlex object
8578bb6a34a8SMatthew G. Knepley 
857995eb5ee5SVaclav Hapla   Notes:
858095eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
858195eb5ee5SVaclav Hapla 
858295eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8583bb6a34a8SMatthew G. Knepley 
8584bb6a34a8SMatthew G. Knepley   Level: developer
8585bb6a34a8SMatthew G. Knepley 
8586db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8587bb6a34a8SMatthew G. Knepley @*/
8588bb6a34a8SMatthew G. Knepley PetscErrorCode DMPlexCheckGeometry(DM dm)
8589bb6a34a8SMatthew G. Knepley {
8590a2a9e04cSMatthew G. Knepley   Vec       coordinates;
8591bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
8592bb6a34a8SMatthew G. Knepley   PetscReal vol;
859351a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
8594bb6a34a8SMatthew G. Knepley 
8595bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
85969566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
85979566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
859851a74b61SMatthew G. Knepley   if (dim != dE) PetscFunctionReturn(0);
85999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8600bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
86019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8602a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
86039566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8604412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8605412e9a14SMatthew G. Knepley     DMPolytopeType ct;
8606412e9a14SMatthew G. Knepley     PetscInt       unsplit;
8607412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
8608412e9a14SMatthew G. Knepley 
86099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
8610412e9a14SMatthew G. Knepley     switch (ct) {
8611412e9a14SMatthew G. Knepley       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8612412e9a14SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8613412e9a14SMatthew G. Knepley       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8614412e9a14SMatthew G. Knepley         ignoreZeroVol = PETSC_TRUE; break;
8615412e9a14SMatthew G. Knepley       default: break;
8616412e9a14SMatthew G. Knepley     }
8617412e9a14SMatthew G. Knepley     switch (ct) {
8618412e9a14SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM:
8619412e9a14SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8620412e9a14SMatthew G. Knepley       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8621a2a9e04cSMatthew G. Knepley       case DM_POLYTOPE_PYRAMID:
8622412e9a14SMatthew G. Knepley         continue;
8623412e9a14SMatthew G. Knepley       default: break;
8624412e9a14SMatthew G. Knepley     }
86259566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8626412e9a14SMatthew G. Knepley     if (unsplit) continue;
86279566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
86281dca8a05SBarry 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);
862963a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol)));
86306858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
86316858538eSMatthew G. Knepley     if (depth > 1) {
86329566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
86331dca8a05SBarry 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);
863463a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol));
8635bb6a34a8SMatthew G. Knepley     }
8636bb6a34a8SMatthew G. Knepley   }
8637bb6a34a8SMatthew G. Knepley   PetscFunctionReturn(0);
8638bb6a34a8SMatthew G. Knepley }
8639bb6a34a8SMatthew G. Knepley 
864003da9461SVaclav Hapla /*@
86417726db96SVaclav Hapla   DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex.
86427726db96SVaclav Hapla 
86437726db96SVaclav Hapla   Collective
864403da9461SVaclav Hapla 
864503da9461SVaclav Hapla   Input Parameters:
86467726db96SVaclav Hapla + dm - The DMPlex object
86477726db96SVaclav Hapla - pointSF - The Point SF, or NULL for Point SF attached to DM
864803da9461SVaclav Hapla 
8649e83a0d2dSVaclav Hapla   Notes:
8650e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
865103da9461SVaclav Hapla 
865295eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
865395eb5ee5SVaclav Hapla 
865403da9461SVaclav Hapla   Level: developer
865503da9461SVaclav Hapla 
8656db781477SPatrick Sanan .seealso: `DMGetPointSF()`, `DMSetFromOptions()`
865703da9461SVaclav Hapla @*/
86587726db96SVaclav Hapla PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF)
865903da9461SVaclav Hapla {
86607726db96SVaclav Hapla   PetscInt        l, nleaves, nroots, overlap;
86617726db96SVaclav Hapla   const PetscInt *locals;
86627726db96SVaclav Hapla   const PetscSFNode *remotes;
8663f0cfc026SVaclav Hapla   PetscBool       distributed;
86647726db96SVaclav Hapla   MPI_Comm        comm;
86657726db96SVaclav Hapla   PetscMPIInt     rank;
866603da9461SVaclav Hapla 
866703da9461SVaclav Hapla   PetscFunctionBegin;
866803da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86697726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
86707726db96SVaclav Hapla   else         pointSF = dm->sf;
86717726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
86727726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
86737726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
86747726db96SVaclav Hapla   {
86757726db96SVaclav Hapla     PetscMPIInt    mpiFlag;
86767726db96SVaclav Hapla 
86777726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag));
86787726db96SVaclav 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);
86797726db96SVaclav Hapla   }
86807726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
86819566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
86827726db96SVaclav Hapla   if (!distributed) {
86837726db96SVaclav 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);
86848918e3e2SVaclav Hapla     PetscFunctionReturn(0);
86858918e3e2SVaclav Hapla   }
86867726db96SVaclav 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);
86877726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
868803da9461SVaclav Hapla 
86897726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
86907726db96SVaclav Hapla   {
86917726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
86927726db96SVaclav Hapla 
86937726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
86947726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
86957726db96SVaclav Hapla     PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots);
86967726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
86977726db96SVaclav Hapla   }
86987726db96SVaclav Hapla 
86997726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
87007726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
87017726db96SVaclav 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);
87027726db96SVaclav Hapla   }
87037726db96SVaclav Hapla 
87047726db96SVaclav Hapla   /* Check there are no cells in interface */
87057726db96SVaclav Hapla   if (!overlap) {
87067726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
87077726db96SVaclav Hapla 
87089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
87099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8710f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
87117726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
8712f5869d18SMatthew G. Knepley 
87137726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
87147726db96SVaclav Hapla     }
871503da9461SVaclav Hapla   }
8716ece87651SVaclav Hapla 
87177726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
87187726db96SVaclav Hapla   {
87197726db96SVaclav Hapla     const PetscInt *rootdegree;
87207726db96SVaclav Hapla 
87217726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
87227726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
8723f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
87247726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
8725f5869d18SMatthew G. Knepley       const PetscInt *cone;
8726f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
8727f5869d18SMatthew G. Knepley 
87289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
87299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
8730f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
8731f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
87327726db96SVaclav Hapla           if (locals) {
87339566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
87347726db96SVaclav Hapla           } else {
87357726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
87367726db96SVaclav Hapla           }
873763a3b9bcSJacob 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]);
8738f5869d18SMatthew G. Knepley         }
8739f5869d18SMatthew G. Knepley       }
8740ece87651SVaclav Hapla     }
87417726db96SVaclav Hapla   }
874203da9461SVaclav Hapla   PetscFunctionReturn(0);
874303da9461SVaclav Hapla }
874403da9461SVaclav Hapla 
87457f9d8d6cSVaclav Hapla /*@
87467f9d8d6cSVaclav Hapla   DMPlexCheck - Perform various checks of Plex sanity
87477f9d8d6cSVaclav Hapla 
87487f9d8d6cSVaclav Hapla   Input Parameter:
87497f9d8d6cSVaclav Hapla . dm - The DMPlex object
87507f9d8d6cSVaclav Hapla 
87517f9d8d6cSVaclav Hapla   Notes:
87527f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
87537f9d8d6cSVaclav Hapla 
87547f9d8d6cSVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
87557f9d8d6cSVaclav Hapla 
87567f9d8d6cSVaclav Hapla   Currently does not include DMPlexCheckCellShape().
87577f9d8d6cSVaclav Hapla 
87587f9d8d6cSVaclav Hapla   Level: developer
87597f9d8d6cSVaclav Hapla 
87607f9d8d6cSVaclav Hapla .seealso: DMCreate(), DMSetFromOptions()
87617f9d8d6cSVaclav Hapla @*/
87627f9d8d6cSVaclav Hapla PetscErrorCode DMPlexCheck(DM dm)
8763b5a892a1SMatthew G. Knepley {
87647f9d8d6cSVaclav Hapla   PetscInt cellHeight;
87657f9d8d6cSVaclav Hapla 
8766b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
87677f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
87689566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
87699566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
87709566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
87719566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
87727726db96SVaclav Hapla   PetscCall(DMPlexCheckPointSF(dm, NULL));
87739566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
8774b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
8775b5a892a1SMatthew G. Knepley }
8776b5a892a1SMatthew G. Knepley 
8777068a5610SStefano Zampini typedef struct cell_stats
8778068a5610SStefano Zampini {
8779068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
8780068a5610SStefano Zampini   PetscInt  count;
8781068a5610SStefano Zampini } cell_stats_t;
8782068a5610SStefano Zampini 
878325befc3bSSatish Balay static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8784068a5610SStefano Zampini {
8785068a5610SStefano Zampini   PetscInt i, N = *len;
8786068a5610SStefano Zampini 
8787068a5610SStefano Zampini   for (i = 0; i < N; i++) {
8788068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *) a;
8789068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *) b;
8790068a5610SStefano Zampini 
8791068a5610SStefano Zampini     B->min = PetscMin(A->min,B->min);
8792068a5610SStefano Zampini     B->max = PetscMax(A->max,B->max);
8793068a5610SStefano Zampini     B->sum += A->sum;
8794068a5610SStefano Zampini     B->squaresum += A->squaresum;
8795068a5610SStefano Zampini     B->count += A->count;
8796068a5610SStefano Zampini   }
8797068a5610SStefano Zampini }
8798068a5610SStefano Zampini 
8799068a5610SStefano Zampini /*@
880043fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8801068a5610SStefano Zampini 
88028261a58bSMatthew G. Knepley   Collective on dm
88038261a58bSMatthew G. Knepley 
8804068a5610SStefano Zampini   Input Parameters:
8805068a5610SStefano Zampini + dm        - The DMPlex object
880643fa8764SMatthew G. Knepley . output    - If true, statistics will be displayed on stdout
880743fa8764SMatthew G. Knepley - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8808068a5610SStefano Zampini 
880995eb5ee5SVaclav Hapla   Notes:
881095eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
881195eb5ee5SVaclav Hapla 
881295eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8813068a5610SStefano Zampini 
8814068a5610SStefano Zampini   Level: developer
8815068a5610SStefano Zampini 
8816db781477SPatrick Sanan .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
8817068a5610SStefano Zampini @*/
881843fa8764SMatthew G. Knepley PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8819068a5610SStefano Zampini {
8820068a5610SStefano Zampini   DM             dmCoarse;
882143fa8764SMatthew G. Knepley   cell_stats_t   stats, globalStats;
882243fa8764SMatthew G. Knepley   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
882343fa8764SMatthew G. Knepley   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
882443fa8764SMatthew G. Knepley   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8825412e9a14SMatthew G. Knepley   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
882643fa8764SMatthew G. Knepley   PetscMPIInt    rank,size;
8827068a5610SStefano Zampini 
8828068a5610SStefano Zampini   PetscFunctionBegin;
8829068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8830068a5610SStefano Zampini   stats.min   = PETSC_MAX_REAL;
8831068a5610SStefano Zampini   stats.max   = PETSC_MIN_REAL;
8832068a5610SStefano Zampini   stats.sum   = stats.squaresum = 0.;
8833068a5610SStefano Zampini   stats.count = 0;
8834068a5610SStefano Zampini 
88359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
88369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
88379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm,&cdim));
88389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
88399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
88409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd));
8841412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
8842068a5610SStefano Zampini     PetscInt  i;
8843068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8844068a5610SStefano Zampini 
88459566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ));
884663a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
884743fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
8848068a5610SStefano Zampini       frobJ    += J[i] * J[i];
8849068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
8850068a5610SStefano Zampini     }
8851068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
8852068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
8853068a5610SStefano Zampini 
8854068a5610SStefano Zampini     stats.min        = PetscMin(stats.min,cond);
8855068a5610SStefano Zampini     stats.max        = PetscMax(stats.max,cond);
8856068a5610SStefano Zampini     stats.sum       += cond;
8857068a5610SStefano Zampini     stats.squaresum += cond2;
8858068a5610SStefano Zampini     stats.count++;
88598261a58bSMatthew G. Knepley     if (output && cond > limit) {
886043fa8764SMatthew G. Knepley       PetscSection coordSection;
886143fa8764SMatthew G. Knepley       Vec          coordsLocal;
886243fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
886343fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
886443fa8764SMatthew G. Knepley 
88659566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
88669566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
88679566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
886863a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond));
886943fa8764SMatthew G. Knepley       for (i = 0; i < Nv/cdim; ++i) {
887063a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
887143fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
88729566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
88739566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d])));
887443fa8764SMatthew G. Knepley         }
88759566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
887643fa8764SMatthew G. Knepley       }
88779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
887843fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize*2; cl += 2) {
887943fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
888043fa8764SMatthew G. Knepley 
888143fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
888243fa8764SMatthew G. Knepley           PetscReal len;
888343fa8764SMatthew G. Knepley 
88849566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
888563a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double) len));
888643fa8764SMatthew G. Knepley         }
888743fa8764SMatthew G. Knepley       }
88889566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
88899566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
889043fa8764SMatthew G. Knepley     }
8891068a5610SStefano Zampini   }
88929566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
8893068a5610SStefano Zampini 
8894068a5610SStefano Zampini   if (size > 1) {
8895068a5610SStefano Zampini     PetscMPIInt   blockLengths[2] = {4,1};
8896068a5610SStefano Zampini     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8897068a5610SStefano Zampini     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8898068a5610SStefano Zampini     MPI_Op        statReduce;
8899068a5610SStefano Zampini 
89009566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType));
89019566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
89029566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
89039566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm));
89049566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
89059566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
8906068a5610SStefano Zampini   } else {
89079566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats,&stats,1));
8908068a5610SStefano Zampini   }
8909dd400576SPatrick Sanan   if (rank == 0) {
8910068a5610SStefano Zampini     count = globalStats.count;
8911068a5610SStefano Zampini     min   = globalStats.min;
8912068a5610SStefano Zampini     max   = globalStats.max;
8913068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
8914068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8915068a5610SStefano Zampini   }
8916068a5610SStefano Zampini 
8917068a5610SStefano Zampini   if (output) {
891863a3b9bcSJacob Faibussowitsch     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));
8919068a5610SStefano Zampini   }
89209566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J,invJ));
8921068a5610SStefano Zampini 
89229566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm,&dmCoarse));
8923068a5610SStefano Zampini   if (dmCoarse) {
8924068a5610SStefano Zampini     PetscBool isplex;
8925068a5610SStefano Zampini 
89269566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex));
89271baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit));
8928068a5610SStefano Zampini   }
8929068a5610SStefano Zampini   PetscFunctionReturn(0);
8930068a5610SStefano Zampini }
8931068a5610SStefano Zampini 
8932f108dbd7SJacob Faibussowitsch /*@
8933f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8934f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
8935f108dbd7SJacob Faibussowitsch 
89366ed19f2fSJacob Faibussowitsch   Collective on dm
8937f108dbd7SJacob Faibussowitsch 
8938f108dbd7SJacob Faibussowitsch   Input Parameters:
8939f108dbd7SJacob Faibussowitsch + dm   - The DMPlex object
8940f108dbd7SJacob Faibussowitsch . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8941f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
8942f108dbd7SJacob Faibussowitsch 
8943f108dbd7SJacob Faibussowitsch   Output Parameters:
8944f108dbd7SJacob Faibussowitsch + OrthQual      - Vec containing orthogonal quality per cell
8945f108dbd7SJacob Faibussowitsch - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8946f108dbd7SJacob Faibussowitsch 
8947f108dbd7SJacob Faibussowitsch   Options Database Keys:
8948f108dbd7SJacob Faibussowitsch + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8949f108dbd7SJacob Faibussowitsch supported.
8950f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8951f108dbd7SJacob Faibussowitsch 
8952f108dbd7SJacob Faibussowitsch   Notes:
8953f108dbd7SJacob Faibussowitsch   Orthogonal quality is given by the following formula:
8954f108dbd7SJacob Faibussowitsch 
8955f108dbd7SJacob Faibussowitsch   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8956f108dbd7SJacob Faibussowitsch 
8957f108dbd7SJacob 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
8958f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8959f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8960f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
8961f108dbd7SJacob Faibussowitsch 
8962f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
8963f108dbd7SJacob Faibussowitsch 
8964f108dbd7SJacob Faibussowitsch   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8965f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8966f108dbd7SJacob Faibussowitsch 
8967f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8968f108dbd7SJacob Faibussowitsch 
8969f108dbd7SJacob Faibussowitsch   Level: intermediate
8970f108dbd7SJacob Faibussowitsch 
8971db781477SPatrick Sanan .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()`
8972f108dbd7SJacob Faibussowitsch @*/
8973f108dbd7SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8974f108dbd7SJacob Faibussowitsch {
89756ed19f2fSJacob Faibussowitsch   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
89766ed19f2fSJacob Faibussowitsch   PetscInt                *idx;
89776ed19f2fSJacob Faibussowitsch   PetscScalar             *oqVals;
8978f108dbd7SJacob Faibussowitsch   const PetscScalar       *cellGeomArr, *faceGeomArr;
89796ed19f2fSJacob Faibussowitsch   PetscReal               *ci, *fi, *Ai;
8980f108dbd7SJacob Faibussowitsch   MPI_Comm                comm;
8981f108dbd7SJacob Faibussowitsch   Vec                     cellgeom, facegeom;
8982f108dbd7SJacob Faibussowitsch   DM                      dmFace, dmCell;
8983f108dbd7SJacob Faibussowitsch   IS                      glob;
8984f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping  ltog;
8985f108dbd7SJacob Faibussowitsch   PetscViewer             vwr;
8986f108dbd7SJacob Faibussowitsch 
8987f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
8988f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89896ed19f2fSJacob Faibussowitsch   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8990f108dbd7SJacob Faibussowitsch   PetscValidPointer(OrthQual, 4);
89916bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol);
89929566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
89939566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
899463a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
89956ed19f2fSJacob Faibussowitsch   {
89966ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
89976ed19f2fSJacob Faibussowitsch 
89989566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
8999f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
9000f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
9001f108dbd7SJacob Faibussowitsch 
90029566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
900398921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
9004f108dbd7SJacob Faibussowitsch     }
90056ed19f2fSJacob Faibussowitsch   }
9006f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
9007f108dbd7SJacob Faibussowitsch     PetscValidPointer(OrthQualLabel, 5);
90089566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
90099566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
90106ed19f2fSJacob Faibussowitsch   } else {*OrthQualLabel = NULL;}
90119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
90129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
90139566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
90149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
90159566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
90169566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
90179566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
90189566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE));
90199566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
90209566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
90219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
90229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
90239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
90249566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
90259566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
90269566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
90279566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
90289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
90296ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
90306ed19f2fSJacob Faibussowitsch     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9031f108dbd7SJacob Faibussowitsch     PetscInt           cellarr[2], *adj = NULL;
9032f108dbd7SJacob Faibussowitsch     PetscScalar        *cArr, *fArr;
9033898cd552SSatish Balay     PetscReal          minvalc = 1.0, minvalf = 1.0;
9034f108dbd7SJacob Faibussowitsch     PetscFVCellGeom    *cg;
9035f108dbd7SJacob Faibussowitsch 
90366ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell-cStart;
9037f108dbd7SJacob Faibussowitsch     cellarr[0] = cell;
9038f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
90399566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
90409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9041f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
90429566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
90436ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
90446ed19f2fSJacob Faibussowitsch       PetscInt         i;
90456ed19f2fSJacob Faibussowitsch       const PetscInt   neigh = adj[cellneigh];
9046f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9047f108dbd7SJacob Faibussowitsch       PetscFVCellGeom  *cgneigh;
9048f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom  *fg;
9049f108dbd7SJacob Faibussowitsch 
9050f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9051f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
90529566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9053f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
90546ed19f2fSJacob Faibussowitsch       {
90556ed19f2fSJacob Faibussowitsch         PetscInt       numcovpts;
90566ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
90576ed19f2fSJacob Faibussowitsch 
90589566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
90599566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
90609566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
90616ed19f2fSJacob Faibussowitsch       }
9062f108dbd7SJacob Faibussowitsch 
9063f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9064f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9065f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9066f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9067f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9068addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9069addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9070addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9071f108dbd7SJacob Faibussowitsch       }
9072addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9073addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9074addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9075f108dbd7SJacob Faibussowitsch 
9076f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9077f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9078f108dbd7SJacob Faibussowitsch         ci[i] = ci[i]/normci;
9079f108dbd7SJacob Faibussowitsch         fi[i] = fi[i]/normfi;
9080f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i]/normai;
9081f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9082f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
9083f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
9084f108dbd7SJacob Faibussowitsch       }
9085f108dbd7SJacob Faibussowitsch       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
9086f108dbd7SJacob Faibussowitsch         minvalc = PetscRealPart(cArr[cellneighiter]);
9087f108dbd7SJacob Faibussowitsch       }
9088f108dbd7SJacob Faibussowitsch       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
9089f108dbd7SJacob Faibussowitsch         minvalf = PetscRealPart(fArr[cellneighiter]);
9090f108dbd7SJacob Faibussowitsch       }
9091f108dbd7SJacob Faibussowitsch     }
90929566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
90939566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9094f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
90956ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9096f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
90979566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9098f108dbd7SJacob Faibussowitsch     }
9099f108dbd7SJacob Faibussowitsch   }
91009566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES));
91019566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
91029566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
91039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
91049566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
91059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9106f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
91079566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9108f108dbd7SJacob Faibussowitsch   }
91099566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
91109566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&vwr));
91119566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
9112f108dbd7SJacob Faibussowitsch   PetscFunctionReturn(0);
9113f108dbd7SJacob Faibussowitsch }
9114f108dbd7SJacob Faibussowitsch 
91151eb70e55SToby Isaac /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
91161eb70e55SToby Isaac  * interpolator construction */
91171eb70e55SToby Isaac static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
91181eb70e55SToby Isaac {
91191eb70e55SToby Isaac   PetscSection   section, newSection, gsection;
91201eb70e55SToby Isaac   PetscSF        sf;
91211eb70e55SToby Isaac   PetscBool      hasConstraints, ghasConstraints;
91221eb70e55SToby Isaac 
91231eb70e55SToby Isaac   PetscFunctionBegin;
91241eb70e55SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
91251eb70e55SToby Isaac   PetscValidPointer(odm,2);
91269566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
91279566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
91289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm)));
91291eb70e55SToby Isaac   if (!ghasConstraints) {
91309566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
91311eb70e55SToby Isaac     *odm = dm;
91321eb70e55SToby Isaac     PetscFunctionReturn(0);
91331eb70e55SToby Isaac   }
91349566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
91359566063dSJacob Faibussowitsch   PetscCall(DMCopyFields(dm, *odm));
91369566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
91379566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
91389566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
91399566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
91409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
91411eb70e55SToby Isaac   PetscFunctionReturn(0);
91421eb70e55SToby Isaac }
91431eb70e55SToby Isaac 
91441eb70e55SToby Isaac static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
91451eb70e55SToby Isaac {
91461eb70e55SToby Isaac   DM             dmco, dmfo;
91471eb70e55SToby Isaac   Mat            interpo;
91481eb70e55SToby Isaac   Vec            rscale;
91491eb70e55SToby Isaac   Vec            cglobalo, clocal;
91501eb70e55SToby Isaac   Vec            fglobal, fglobalo, flocal;
91511eb70e55SToby Isaac   PetscBool      regular;
91521eb70e55SToby Isaac 
91531eb70e55SToby Isaac   PetscFunctionBegin;
91549566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
91559566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
91569566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
91579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
91589566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
91599566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
91609566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
91619566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
91629566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
91639566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
91649566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
91659566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
91669566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
91679566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
91689566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
91699566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
91709566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
91719566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
91729566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
91739566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
91749566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
91759566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
91769566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
91779566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
91781eb70e55SToby Isaac   *shift = fglobal;
91799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
91809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
91819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
91829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
91839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
91849566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
91859566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
91869566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
91871eb70e55SToby Isaac   PetscFunctionReturn(0);
91881eb70e55SToby Isaac }
91891eb70e55SToby Isaac 
91901eb70e55SToby Isaac PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
91911eb70e55SToby Isaac {
91921eb70e55SToby Isaac   PetscObject    shifto;
91931eb70e55SToby Isaac   Vec            shift;
91941eb70e55SToby Isaac 
91951eb70e55SToby Isaac   PetscFunctionBegin;
91961eb70e55SToby Isaac   if (!interp) {
91971eb70e55SToby Isaac     Vec rscale;
91981eb70e55SToby Isaac 
91999566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
92009566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
92011eb70e55SToby Isaac   } else {
92029566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
92031eb70e55SToby Isaac   }
92049566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
92051eb70e55SToby Isaac   if (!shifto) {
92069566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
92079566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift));
92081eb70e55SToby Isaac     shifto = (PetscObject) shift;
92099566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
92101eb70e55SToby Isaac   }
92111eb70e55SToby Isaac   shift = (Vec) shifto;
92129566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
92139566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
92149566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
92151eb70e55SToby Isaac   PetscFunctionReturn(0);
92161eb70e55SToby Isaac }
92171eb70e55SToby Isaac 
9218bceba477SMatthew G. Knepley /* Pointwise interpolation
9219bceba477SMatthew G. Knepley      Just code FEM for now
9220bceba477SMatthew G. Knepley      u^f = I u^c
92214ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
92224ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
92234ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
9224bceba477SMatthew G. Knepley */
9225bceba477SMatthew G. Knepley PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9226bceba477SMatthew G. Knepley {
9227bceba477SMatthew G. Knepley   PetscSection   gsc, gsf;
9228bceba477SMatthew G. Knepley   PetscInt       m, n;
9229a063dac3SMatthew G. Knepley   void          *ctx;
923068132eb9SMatthew G. Knepley   DM             cdm;
9231cf51de39SMatthew G. Knepley   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9232bceba477SMatthew G. Knepley 
9233bceba477SMatthew G. Knepley   PetscFunctionBegin;
92349566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
92359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
92369566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
92379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
923868132eb9SMatthew G. Knepley 
92399566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
92409566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation));
92419566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
92429566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
92439566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
924468132eb9SMatthew G. Knepley 
92459566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
92469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
92479566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
92489566063dSJacob Faibussowitsch   else                                            PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
92499566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
92504db47ee9SStefano Zampini   if (scaling) {
92515d1c2e58SMatthew G. Knepley     /* Use naive scaling */
92529566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
92534db47ee9SStefano Zampini   }
9254a063dac3SMatthew G. Knepley   PetscFunctionReturn(0);
9255a063dac3SMatthew G. Knepley }
9256bceba477SMatthew G. Knepley 
92576dbf9973SLawrence Mitchell PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9258a063dac3SMatthew G. Knepley {
92596dbf9973SLawrence Mitchell   VecScatter     ctx;
926090748bafSMatthew G. Knepley 
9261a063dac3SMatthew G. Knepley   PetscFunctionBegin;
92629566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
92639566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
92649566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
9265bceba477SMatthew G. Knepley   PetscFunctionReturn(0);
9266bceba477SMatthew G. Knepley }
9267bceba477SMatthew G. Knepley 
92683e9753d6SMatthew G. Knepley static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
92693e9753d6SMatthew G. Knepley                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
92703e9753d6SMatthew G. Knepley                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
92713e9753d6SMatthew G. Knepley                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
92723e9753d6SMatthew G. Knepley {
927300635df3SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
927400635df3SMatthew G. Knepley   PetscInt       c;
927500635df3SMatthew G. Knepley   for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0;
92763e9753d6SMatthew G. Knepley }
92773e9753d6SMatthew G. Knepley 
9278b4937a87SMatthew G. Knepley PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9279b4937a87SMatthew G. Knepley {
9280b4937a87SMatthew G. Knepley   DM             dmc;
9281b4937a87SMatthew G. Knepley   PetscDS        ds;
9282b4937a87SMatthew G. Knepley   Vec            ones, locmass;
9283b4937a87SMatthew G. Knepley   IS             cellIS;
9284b4937a87SMatthew G. Knepley   PetscFormKey   key;
9285b4937a87SMatthew G. Knepley   PetscInt       depth;
9286b4937a87SMatthew G. Knepley 
9287b4937a87SMatthew G. Knepley   PetscFunctionBegin;
92889566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
92899566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
92909566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
92919566063dSJacob Faibussowitsch   PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
92929566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmc, mass));
92939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &ones));
92949566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &locmass));
92959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmc, &depth));
92969566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
92979566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
92989566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
9299b4937a87SMatthew G. Knepley   key.label = NULL;
9300b4937a87SMatthew G. Knepley   key.value = 0;
9301b4937a87SMatthew G. Knepley   key.field = 0;
9302b4937a87SMatthew G. Knepley   key.part  = 0;
93039566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
93049566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
93059566063dSJacob Faibussowitsch   PetscCall(VecSet(*mass, 0.0));
93069566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
93079566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
93089566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &ones));
93099566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &locmass));
93109566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
9311b4937a87SMatthew G. Knepley   PetscFunctionReturn(0);
9312b4937a87SMatthew G. Knepley }
9313b4937a87SMatthew G. Knepley 
9314bd041c0cSMatthew G. Knepley PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9315bd041c0cSMatthew G. Knepley {
9316bd041c0cSMatthew G. Knepley   PetscSection   gsc, gsf;
9317bd041c0cSMatthew G. Knepley   PetscInt       m, n;
9318bd041c0cSMatthew G. Knepley   void          *ctx;
9319bd041c0cSMatthew G. Knepley   DM             cdm;
9320bd041c0cSMatthew G. Knepley   PetscBool      regular;
9321bd041c0cSMatthew G. Knepley 
9322bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
93233e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
93243e9753d6SMatthew G. Knepley     DM            dmc;
93253e9753d6SMatthew G. Knepley     PetscDS       ds;
9326b4937a87SMatthew G. Knepley     PetscWeakForm wf;
93273e9753d6SMatthew G. Knepley     Vec           u;
93283e9753d6SMatthew G. Knepley     IS            cellIS;
932906ad1575SMatthew G. Knepley     PetscFormKey  key;
93303e9753d6SMatthew G. Knepley     PetscInt      depth;
93313e9753d6SMatthew G. Knepley 
93329566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
93339566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
93349566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
93359566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
93369566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
93379566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
93389566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
93399566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmc, &u));
93409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
93419566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
93429566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
93436528b96dSMatthew G. Knepley     key.label = NULL;
93446528b96dSMatthew G. Knepley     key.value = 0;
93456528b96dSMatthew G. Knepley     key.field = 0;
934606ad1575SMatthew G. Knepley     key.part  = 0;
93479566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
93489566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
93499566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmc, &u));
93509566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
93513e9753d6SMatthew G. Knepley   } else {
93529566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
93539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
93549566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
93559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
9356bd041c0cSMatthew G. Knepley 
93579566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass));
93589566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
93599566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
93609566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
9361bd041c0cSMatthew G. Knepley 
93629566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
93639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
93649566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
93659566063dSJacob Faibussowitsch     else                            PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
93663e9753d6SMatthew G. Knepley   }
93679566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
9368bd041c0cSMatthew G. Knepley   PetscFunctionReturn(0);
9369bd041c0cSMatthew G. Knepley }
9370bd041c0cSMatthew G. Knepley 
93710aef6b92SMatthew G. Knepley /*@
93720aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
93730aef6b92SMatthew G. Knepley 
93740aef6b92SMatthew G. Knepley   Input Parameter:
93750aef6b92SMatthew G. Knepley . dm - The DMPlex object
93760aef6b92SMatthew G. Knepley 
93770aef6b92SMatthew G. Knepley   Output Parameter:
93780aef6b92SMatthew G. Knepley . regular - The flag
93790aef6b92SMatthew G. Knepley 
93800aef6b92SMatthew G. Knepley   Level: intermediate
93810aef6b92SMatthew G. Knepley 
9382db781477SPatrick Sanan .seealso: `DMPlexSetRegularRefinement()`
93830aef6b92SMatthew G. Knepley @*/
93840aef6b92SMatthew G. Knepley PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
93850aef6b92SMatthew G. Knepley {
93860aef6b92SMatthew G. Knepley   PetscFunctionBegin;
93870aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9388dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(regular, 2);
93890aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *) dm->data)->regularRefinement;
93900aef6b92SMatthew G. Knepley   PetscFunctionReturn(0);
93910aef6b92SMatthew G. Knepley }
93920aef6b92SMatthew G. Knepley 
93930aef6b92SMatthew G. Knepley /*@
93940aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
93950aef6b92SMatthew G. Knepley 
93960aef6b92SMatthew G. Knepley   Input Parameters:
93970aef6b92SMatthew G. Knepley + dm - The DMPlex object
93980aef6b92SMatthew G. Knepley - regular - The flag
93990aef6b92SMatthew G. Knepley 
94000aef6b92SMatthew G. Knepley   Level: intermediate
94010aef6b92SMatthew G. Knepley 
9402db781477SPatrick Sanan .seealso: `DMPlexGetRegularRefinement()`
94030aef6b92SMatthew G. Knepley @*/
94040aef6b92SMatthew G. Knepley PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
94050aef6b92SMatthew G. Knepley {
94060aef6b92SMatthew G. Knepley   PetscFunctionBegin;
94070aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
94080aef6b92SMatthew G. Knepley   ((DM_Plex *) dm->data)->regularRefinement = regular;
94090aef6b92SMatthew G. Knepley   PetscFunctionReturn(0);
94100aef6b92SMatthew G. Knepley }
94110aef6b92SMatthew G. Knepley 
9412f7c74593SToby Isaac /* anchors */
9413a68b90caSToby Isaac /*@
9414f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9415ebdb1bfaSJed Brown   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints().
9416a68b90caSToby Isaac 
9417e228b242SToby Isaac   not collective
9418a68b90caSToby Isaac 
9419f899ff85SJose E. Roman   Input Parameter:
9420a68b90caSToby Isaac . dm - The DMPlex object
9421a68b90caSToby Isaac 
9422a68b90caSToby Isaac   Output Parameters:
9423a68b90caSToby Isaac + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9424a68b90caSToby Isaac - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9425a68b90caSToby Isaac 
9426a68b90caSToby Isaac   Level: intermediate
9427a68b90caSToby Isaac 
9428db781477SPatrick Sanan .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9429a68b90caSToby Isaac @*/
9430a17985deSToby Isaac PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9431a68b90caSToby Isaac {
9432a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
9433a68b90caSToby Isaac 
9434a68b90caSToby Isaac   PetscFunctionBegin;
9435a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
94369566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
9437a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
9438a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
9439a68b90caSToby Isaac   PetscFunctionReturn(0);
9440a68b90caSToby Isaac }
9441a68b90caSToby Isaac 
9442a68b90caSToby Isaac /*@
9443f7c74593SToby Isaac   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9444f7c74593SToby Isaac   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9445a68b90caSToby Isaac   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9446a68b90caSToby Isaac 
9447a17985deSToby Isaac   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9448ebdb1bfaSJed Brown   DMGetDefaultConstraints() and filling in the entries in the constraint matrix.
9449a68b90caSToby Isaac 
9450e228b242SToby Isaac   collective on dm
9451a68b90caSToby Isaac 
9452a68b90caSToby Isaac   Input Parameters:
9453a68b90caSToby Isaac + dm - The DMPlex object
9454e228b242SToby 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).
9455e228b242SToby Isaac - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9456a68b90caSToby Isaac 
9457a68b90caSToby Isaac   The reference counts of anchorSection and anchorIS are incremented.
9458a68b90caSToby Isaac 
9459a68b90caSToby Isaac   Level: intermediate
9460a68b90caSToby Isaac 
9461db781477SPatrick Sanan .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9462a68b90caSToby Isaac @*/
9463a17985deSToby Isaac PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9464a68b90caSToby Isaac {
9465a68b90caSToby Isaac   DM_Plex        *plex = (DM_Plex *)dm->data;
9466e228b242SToby Isaac   PetscMPIInt    result;
9467a68b90caSToby Isaac 
9468a68b90caSToby Isaac   PetscFunctionBegin;
9469a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9470e228b242SToby Isaac   if (anchorSection) {
9471e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
94729566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result));
94731dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9474e228b242SToby Isaac   }
9475e228b242SToby Isaac   if (anchorIS) {
9476e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
94779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result));
94781dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9479e228b242SToby Isaac   }
9480a68b90caSToby Isaac 
94819566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
94829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
9483a68b90caSToby Isaac   plex->anchorSection = anchorSection;
9484a68b90caSToby Isaac 
94859566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
94869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
9487a68b90caSToby Isaac   plex->anchorIS = anchorIS;
9488a68b90caSToby Isaac 
9489cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9490a68b90caSToby Isaac     PetscInt size, a, pStart, pEnd;
9491a68b90caSToby Isaac     const PetscInt *anchors;
9492a68b90caSToby Isaac 
94939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd));
94949566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS,&size));
94959566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS,&anchors));
9496a68b90caSToby Isaac     for (a = 0; a < size; a++) {
9497a68b90caSToby Isaac       PetscInt p;
9498a68b90caSToby Isaac 
9499a68b90caSToby Isaac       p = anchors[a];
9500a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
9501a68b90caSToby Isaac         PetscInt dof;
9502a68b90caSToby Isaac 
95039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection,p,&dof));
9504a68b90caSToby Isaac         if (dof) {
9505a68b90caSToby Isaac 
95069566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS,&anchors));
950763a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p);
9508a68b90caSToby Isaac         }
9509a68b90caSToby Isaac       }
9510a68b90caSToby Isaac     }
95119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS,&anchors));
9512a68b90caSToby Isaac   }
9513f7c74593SToby Isaac   /* reset the generic constraints */
95149566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL));
9515a68b90caSToby Isaac   PetscFunctionReturn(0);
9516a68b90caSToby Isaac }
9517a68b90caSToby Isaac 
9518f7c74593SToby Isaac static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9519a68b90caSToby Isaac {
9520f7c74593SToby Isaac   PetscSection anchorSection;
95216995de1eSToby Isaac   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9522a68b90caSToby Isaac 
9523a68b90caSToby Isaac   PetscFunctionBegin;
9524a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL));
95269566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec));
95279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section,&numFields));
95286995de1eSToby Isaac   if (numFields) {
9529719ab38cSToby Isaac     PetscInt f;
95309566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec,numFields));
9531719ab38cSToby Isaac 
9532719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
9533719ab38cSToby Isaac       PetscInt numComp;
9534719ab38cSToby Isaac 
95359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section,f,&numComp));
95369566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp));
9537719ab38cSToby Isaac     }
95386995de1eSToby Isaac   }
95399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd));
95409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section,&sStart,&sEnd));
95416995de1eSToby Isaac   pStart = PetscMax(pStart,sStart);
95426995de1eSToby Isaac   pEnd   = PetscMin(pEnd,sEnd);
95436995de1eSToby Isaac   pEnd   = PetscMax(pStart,pEnd);
95449566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd));
9545a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
95469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection,p,&dof));
9547a68b90caSToby Isaac     if (dof) {
95489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,p,&dof));
95499566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec,p,dof));
9550a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
95519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section,p,f,&dof));
95529566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof));
9553a68b90caSToby Isaac       }
9554a68b90caSToby Isaac     }
9555a68b90caSToby Isaac   }
95569566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
95579566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section"));
9558a68b90caSToby Isaac   PetscFunctionReturn(0);
9559a68b90caSToby Isaac }
9560a68b90caSToby Isaac 
9561f7c74593SToby Isaac static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9562a68b90caSToby Isaac {
9563f7c74593SToby Isaac   PetscSection   aSec;
9564ae65431dSMatthew G. Knepley   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
95650ac89760SToby Isaac   const PetscInt *anchors;
95660ac89760SToby Isaac   PetscInt       numFields, f;
956766ad2231SToby Isaac   IS             aIS;
9568e19f7ee6SMark Adams   MatType        mtype;
9569e19f7ee6SMark Adams   PetscBool      iscuda,iskokkos;
95700ac89760SToby Isaac 
95710ac89760SToby Isaac   PetscFunctionBegin;
95720ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
95749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
95759566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF,cMat));
95769566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat,m,n,m,n));
95779566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda));
95789566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda));
95799566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos));
95809566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos));
9581e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9582e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9583e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
95849566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat,mtype));
95859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS));
95869566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
95876995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
95889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd));
95899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section,&sStart,&sEnd));
95909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m+1,&i));
95910ac89760SToby Isaac   i[0] = 0;
95929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section,&numFields));
95930ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
9594f19733c5SToby Isaac     PetscInt rDof, rOff, r;
9595f19733c5SToby Isaac 
95969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec,p,&rDof));
9597f19733c5SToby Isaac     if (!rDof) continue;
95989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec,p,&rOff));
95990ac89760SToby Isaac     if (numFields) {
96000ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
96010ac89760SToby Isaac         annz = 0;
9602f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
9603f19733c5SToby Isaac           a = anchors[rOff + r];
9604ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
96059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof));
96060ac89760SToby Isaac           annz += aDof;
96070ac89760SToby Isaac         }
96089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof));
96099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off));
96100ac89760SToby Isaac         for (q = 0; q < dof; q++) {
96110ac89760SToby Isaac           i[off + q + 1] = i[off + q] + annz;
96120ac89760SToby Isaac         }
96130ac89760SToby Isaac       }
96142f7452b8SBarry Smith     } else {
96150ac89760SToby Isaac       annz = 0;
96169566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&dof));
96170ac89760SToby Isaac       for (q = 0; q < dof; q++) {
9618ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
9619ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
96209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section,a,&aDof));
96210ac89760SToby Isaac         annz += aDof;
96220ac89760SToby Isaac       }
96239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&dof));
96249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec,p,&off));
96250ac89760SToby Isaac       for (q = 0; q < dof; q++) {
96260ac89760SToby Isaac         i[off + q + 1] = i[off + q] + annz;
96270ac89760SToby Isaac       }
96280ac89760SToby Isaac     }
96290ac89760SToby Isaac   }
96300ac89760SToby Isaac   nnz = i[m];
96319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz,&j));
96320ac89760SToby Isaac   offset = 0;
96330ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
96340ac89760SToby Isaac     if (numFields) {
96350ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
96369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof));
96370ac89760SToby Isaac         for (q = 0; q < dof; q++) {
96380ac89760SToby Isaac           PetscInt rDof, rOff, r;
96399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec,p,&rDof));
96409566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec,p,&rOff));
96410ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
96420ac89760SToby Isaac             PetscInt s;
96430ac89760SToby Isaac 
96440ac89760SToby Isaac             a = anchors[rOff + r];
9645ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
96469566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof));
96479566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff));
96480ac89760SToby Isaac             for (s = 0; s < aDof; s++) {
96490ac89760SToby Isaac               j[offset++] = aOff + s;
96500ac89760SToby Isaac             }
96510ac89760SToby Isaac           }
96520ac89760SToby Isaac         }
96530ac89760SToby Isaac       }
96542f7452b8SBarry Smith     } else {
96559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&dof));
96560ac89760SToby Isaac       for (q = 0; q < dof; q++) {
96570ac89760SToby Isaac         PetscInt rDof, rOff, r;
96589566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,p,&rDof));
96599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&rOff));
96600ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
96610ac89760SToby Isaac           PetscInt s;
96620ac89760SToby Isaac 
96630ac89760SToby Isaac           a = anchors[rOff + r];
9664ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
96659566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,a,&aDof));
96669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section,a,&aOff));
96670ac89760SToby Isaac           for (s = 0; s < aDof; s++) {
96680ac89760SToby Isaac             j[offset++] = aOff + s;
96690ac89760SToby Isaac           }
96700ac89760SToby Isaac         }
96710ac89760SToby Isaac       }
96720ac89760SToby Isaac     }
96730ac89760SToby Isaac   }
96749566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL));
96759566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
96769566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
96779566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
96780ac89760SToby Isaac   PetscFunctionReturn(0);
96790ac89760SToby Isaac }
96800ac89760SToby Isaac 
968166ad2231SToby Isaac PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
968266ad2231SToby Isaac {
9683f7c74593SToby Isaac   DM_Plex        *plex = (DM_Plex *)dm->data;
9684f7c74593SToby Isaac   PetscSection   anchorSection, section, cSec;
968566ad2231SToby Isaac   Mat            cMat;
968666ad2231SToby Isaac 
968766ad2231SToby Isaac   PetscFunctionBegin;
968866ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
96899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL));
969066ad2231SToby Isaac   if (anchorSection) {
969144a7f3ddSMatthew G. Knepley     PetscInt Nf;
9692e228b242SToby Isaac 
96939566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm,&section));
96949566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec));
96959566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat));
96969566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm,&Nf));
96979566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat));
96989566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL));
96999566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
97009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
970166ad2231SToby Isaac   }
970266ad2231SToby Isaac   PetscFunctionReturn(0);
970366ad2231SToby Isaac }
9704a93c429eSMatthew G. Knepley 
9705a93c429eSMatthew G. Knepley PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9706a93c429eSMatthew G. Knepley {
9707a93c429eSMatthew G. Knepley   IS             subis;
9708a93c429eSMatthew G. Knepley   PetscSection   section, subsection;
9709a93c429eSMatthew G. Knepley 
9710a93c429eSMatthew G. Knepley   PetscFunctionBegin;
97119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
971228b400f6SJacob Faibussowitsch   PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
971328b400f6SJacob Faibussowitsch   PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9714a93c429eSMatthew G. Knepley   /* Create subdomain */
97159566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dm, label, value, subdm));
9716a93c429eSMatthew G. Knepley   /* Create submodel */
97179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
97189566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
97199566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
97209566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
97219566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
9722a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
9723a93c429eSMatthew G. Knepley   if (is) {
9724a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
9725a93c429eSMatthew G. Knepley     IS              spIS;
9726a93c429eSMatthew G. Knepley     const PetscInt *spmap;
9727a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
9728a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9729a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9730a93c429eSMatthew G. Knepley 
97319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
97329566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
97339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
97349566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
97359566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
97369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
9737a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
9738a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize  = 0;
9739a93c429eSMatthew G. Knepley 
97409566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
9741a93c429eSMatthew G. Knepley       if (gdof > 0) {
9742a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
9743a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
9744a93c429eSMatthew G. Knepley 
97459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
97469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
9747a93c429eSMatthew G. Knepley           pSubSize += fdof-fcdof;
9748a93c429eSMatthew G. Knepley         }
9749a93c429eSMatthew G. Knepley         subSize += pSubSize;
9750a93c429eSMatthew G. Knepley         if (pSubSize) {
9751a93c429eSMatthew G. Knepley           if (bs < 0) {
9752a93c429eSMatthew G. Knepley             bs = pSubSize;
9753a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
9754a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
9755a93c429eSMatthew G. Knepley             bs = 1;
9756a93c429eSMatthew G. Knepley           }
9757a93c429eSMatthew G. Knepley         }
9758a93c429eSMatthew G. Knepley       }
9759a93c429eSMatthew G. Knepley     }
9760a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
9761a93c429eSMatthew G. Knepley     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
97629566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax));
9763a93c429eSMatthew G. Knepley     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9764a93c429eSMatthew G. Knepley     else                            {bs = bsMinMax[0];}
97659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
9766a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
9767a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
9768a93c429eSMatthew G. Knepley 
97699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
9770a93c429eSMatthew G. Knepley       if (gdof > 0) {
9771a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
9772a93c429eSMatthew G. Knepley 
97739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
9774a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
9775a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
9776a93c429eSMatthew G. Knepley 
9777a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
9778a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
97799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
97809566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
9781a93c429eSMatthew G. Knepley             poff += fdof-fcdof;
9782a93c429eSMatthew G. Knepley           }
97839566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
97849566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
9785a93c429eSMatthew G. Knepley           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9786a93c429eSMatthew G. Knepley             subIndices[subOff] = goff+poff+fc;
9787a93c429eSMatthew G. Knepley           }
9788a93c429eSMatthew G. Knepley         }
9789a93c429eSMatthew G. Knepley       }
9790a93c429eSMatthew G. Knepley     }
97919566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
97929566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
9793a93c429eSMatthew G. Knepley     if (bs > 1) {
9794a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
9795a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
9796a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
9797a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
9798a93c429eSMatthew G. Knepley           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9799a93c429eSMatthew G. Knepley         }
9800a93c429eSMatthew G. Knepley       }
98019566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
9802a93c429eSMatthew G. Knepley     }
9803a93c429eSMatthew G. Knepley     /* Attach nullspace */
9804a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
9805a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9806a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
9807a93c429eSMatthew G. Knepley     }
9808a93c429eSMatthew G. Knepley     if (f < Nf) {
9809a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
98109566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
98116823f3c5SBlaise Bourdin 
98129566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace));
98139566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
9814a93c429eSMatthew G. Knepley     }
9815a93c429eSMatthew G. Knepley   }
9816a93c429eSMatthew G. Knepley   PetscFunctionReturn(0);
9817a93c429eSMatthew G. Knepley }
9818c0f0dcc3SMatthew G. Knepley 
9819c0f0dcc3SMatthew G. Knepley /*@
9820c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9821c0f0dcc3SMatthew G. Knepley 
9822c0f0dcc3SMatthew G. Knepley   Input Parameter:
9823c0f0dcc3SMatthew G. Knepley - dm - The DM
9824c0f0dcc3SMatthew G. Knepley 
9825c0f0dcc3SMatthew G. Knepley   Level: developer
9826c0f0dcc3SMatthew G. Knepley 
9827c0f0dcc3SMatthew G. Knepley   Options Database Keys:
9828c0f0dcc3SMatthew G. Knepley . -dm_plex_monitor_throughput - Activate the monitor
9829c0f0dcc3SMatthew G. Knepley 
9830db781477SPatrick Sanan .seealso: `DMSetFromOptions()`, `DMPlexCreate()`
9831c0f0dcc3SMatthew G. Knepley @*/
9832c0f0dcc3SMatthew G. Knepley PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9833c0f0dcc3SMatthew G. Knepley {
9834e5ed2c37SJose E. Roman #if defined(PETSC_USE_LOG)
9835c0f0dcc3SMatthew G. Knepley   PetscStageLog      stageLog;
9836c0f0dcc3SMatthew G. Knepley   PetscLogEvent      event;
9837c0f0dcc3SMatthew G. Knepley   PetscLogStage      stage;
9838c0f0dcc3SMatthew G. Knepley   PetscEventPerfInfo eventInfo;
9839c0f0dcc3SMatthew G. Knepley   PetscReal          cellRate, flopRate;
9840c0f0dcc3SMatthew G. Knepley   PetscInt           cStart, cEnd, Nf, N;
9841c0f0dcc3SMatthew G. Knepley   const char        *name;
9842e5ed2c37SJose E. Roman #endif
9843c0f0dcc3SMatthew G. Knepley 
9844c0f0dcc3SMatthew G. Knepley   PetscFunctionBegin;
9845c0f0dcc3SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9846c0f0dcc3SMatthew G. Knepley #if defined(PETSC_USE_LOG)
98479566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
98489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
98499566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
98509566063dSJacob Faibussowitsch   PetscCall(PetscLogGetStageLog(&stageLog));
98519566063dSJacob Faibussowitsch   PetscCall(PetscStageLogGetCurrent(stageLog, &stage));
98529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
98539566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo));
9854c0f0dcc3SMatthew G. Knepley   N        = (cEnd - cStart)*Nf*eventInfo.count;
9855c0f0dcc3SMatthew G. Knepley   flopRate = eventInfo.flops/eventInfo.time;
9856c0f0dcc3SMatthew G. Knepley   cellRate = N/eventInfo.time;
985763a3b9bcSJacob 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)));
9858c0f0dcc3SMatthew G. Knepley #else
9859c0f0dcc3SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9860c0f0dcc3SMatthew G. Knepley #endif
9861c0f0dcc3SMatthew G. Knepley   PetscFunctionReturn(0);
9862c0f0dcc3SMatthew G. Knepley }
9863