xref: /petsc/src/dm/impls/plex/plex.c (revision 9fca9976580a661c418fd9281b99affbad84f0a0)
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));
6212c40f234SMatthew G. Knepley   } else {
6229566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(v, viewer));
6232c40f234SMatthew G. Knepley   }
6242c40f234SMatthew G. Knepley   PetscFunctionReturn(0);
6252c40f234SMatthew G. Knepley }
6262c40f234SMatthew G. Knepley 
6272c40f234SMatthew G. Knepley PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
6282c40f234SMatthew G. Knepley {
6292c40f234SMatthew G. Knepley   DM             dm;
6306823f3c5SBlaise Bourdin   PetscBool      ishdf5,isexodusii;
6312c40f234SMatthew G. Knepley 
6322c40f234SMatthew G. Knepley   PetscFunctionBegin;
6339566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
63428b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
6369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii));
6372c40f234SMatthew G. Knepley   if (ishdf5) {
638878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6399566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
640b136c2c9SMatthew G. Knepley #else
641b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
642878b459fSMatthew G. Knepley #endif
6436823f3c5SBlaise Bourdin   } else if (isexodusii) {
6446823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
6459566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
6466823f3c5SBlaise Bourdin #else
6476823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
6486823f3c5SBlaise Bourdin #endif
6492c40f234SMatthew G. Knepley   } else {
6509566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(v, viewer));
651552f7358SJed Brown   }
652552f7358SJed Brown   PetscFunctionReturn(0);
653552f7358SJed Brown }
654552f7358SJed Brown 
655d930f514SMatthew G. Knepley PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
656d930f514SMatthew G. Knepley {
657d930f514SMatthew G. Knepley   DM                dm;
658d930f514SMatthew G. Knepley   PetscViewerFormat format;
659d930f514SMatthew G. Knepley   PetscBool         ishdf5;
660d930f514SMatthew G. Knepley 
661d930f514SMatthew G. Knepley   PetscFunctionBegin;
6629566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
66328b400f6SJacob Faibussowitsch   PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6649566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
6659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
666d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
667a8ad634aSStefano Zampini     if (dm->useNatural) {
668d930f514SMatthew G. Knepley       if (dm->sfNatural) {
669d930f514SMatthew G. Knepley         if (ishdf5) {
670d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
671d930f514SMatthew G. Knepley           Vec         v;
672d930f514SMatthew G. Knepley           const char *vecname;
673d930f514SMatthew G. Knepley 
6749566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalVector(dm, &v));
6759566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname));
6769566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject) v, vecname));
6779566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
6789566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
6799566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
6809566063dSJacob Faibussowitsch           PetscCall(DMRestoreGlobalVector(dm, &v));
681d930f514SMatthew G. Knepley #else
682d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
683d930f514SMatthew G. Knepley #endif
684d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
685d930f514SMatthew G. Knepley       }
686a8ad634aSStefano Zampini     } else {
6879566063dSJacob Faibussowitsch       PetscCall(VecLoad_Default(originalv, viewer));
688a8ad634aSStefano Zampini     }
689d930f514SMatthew G. Knepley   }
690d930f514SMatthew G. Knepley   PetscFunctionReturn(0);
691d930f514SMatthew G. Knepley }
692d930f514SMatthew G. Knepley 
6937cd05799SMatthew G. Knepley PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
694731e8ddeSMatthew G. Knepley {
695731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
696731e8ddeSMatthew G. Knepley   Vec                coordinates;
697ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
698731e8ddeSMatthew G. Knepley   const char        *name[4];
699731e8ddeSMatthew G. Knepley   const PetscScalar *a;
700731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
701731e8ddeSMatthew G. Knepley 
702731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
7039566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
7049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
7059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
7079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
7089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
7109566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
711731e8ddeSMatthew G. Knepley   name[0]     = "vertex";
712731e8ddeSMatthew G. Knepley   name[1]     = "edge";
713731e8ddeSMatthew G. Knepley   name[dim-1] = "face";
714731e8ddeSMatthew G. Knepley   name[dim]   = "cell";
715731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
716731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
717ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
718731e8ddeSMatthew G. Knepley 
7199566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
72063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
7219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7229566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
723731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
724731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
725731e8ddeSMatthew G. Knepley 
726731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
7279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
728731e8ddeSMatthew G. Knepley       if (!dof) continue;
7299566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
7309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
73163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
732731e8ddeSMatthew G. Knepley       for (p = 0; p < dof/dim; ++p) {
7339566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
734731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
7359566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
7369566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d])));
737731e8ddeSMatthew G. Knepley         }
7389566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
739731e8ddeSMatthew G. Knepley       }
7409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
741731e8ddeSMatthew G. Knepley     }
7429566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
7439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
744731e8ddeSMatthew G. Knepley   }
7459566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
746731e8ddeSMatthew G. Knepley   PetscFunctionReturn(0);
747731e8ddeSMatthew G. Knepley }
748731e8ddeSMatthew G. Knepley 
74919ad8254SMatthew G. Knepley typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem;
75019ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
75119ad8254SMatthew G. Knepley 
75219ad8254SMatthew G. Knepley static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
75319ad8254SMatthew G. Knepley {
75419ad8254SMatthew G. Knepley   PetscInt       i;
75519ad8254SMatthew G. Knepley 
75619ad8254SMatthew G. Knepley   PetscFunctionBegin;
75719ad8254SMatthew G. Knepley   if (dim > 3) {
7589566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i])));
75919ad8254SMatthew G. Knepley   } else {
760bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
76119ad8254SMatthew G. Knepley 
76219ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
76319ad8254SMatthew G. Knepley     switch (cs) {
76419ad8254SMatthew G. Knepley       case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break;
76519ad8254SMatthew G. Knepley       case CS_POLAR:
76663a3b9bcSJacob Faibussowitsch         PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
76719ad8254SMatthew G. Knepley         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
76819ad8254SMatthew G. Knepley         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
76919ad8254SMatthew G. Knepley         break;
77019ad8254SMatthew G. Knepley       case CS_CYLINDRICAL:
77163a3b9bcSJacob Faibussowitsch         PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
77219ad8254SMatthew G. Knepley         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
77319ad8254SMatthew G. Knepley         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
77419ad8254SMatthew G. Knepley         trcoords[2] = coords[2];
77519ad8254SMatthew G. Knepley         break;
77619ad8254SMatthew G. Knepley       case CS_SPHERICAL:
77763a3b9bcSJacob Faibussowitsch         PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
77819ad8254SMatthew G. Knepley         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
77919ad8254SMatthew G. Knepley         trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
78019ad8254SMatthew G. Knepley         trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
78119ad8254SMatthew G. Knepley         break;
78219ad8254SMatthew G. Knepley     }
7839566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i]));
78419ad8254SMatthew G. Knepley   }
78519ad8254SMatthew G. Knepley   PetscFunctionReturn(0);
78619ad8254SMatthew G. Knepley }
78719ad8254SMatthew G. Knepley 
7887cd05799SMatthew G. Knepley static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
789552f7358SJed Brown {
790552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex*) dm->data;
791552f7358SJed Brown   DM                cdm;
792552f7358SJed Brown   PetscSection      coordSection;
793552f7358SJed Brown   Vec               coordinates;
794552f7358SJed Brown   PetscViewerFormat format;
795552f7358SJed Brown 
796552f7358SJed Brown   PetscFunctionBegin;
7979566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
7989566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
7999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8009566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
801552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
802552f7358SJed Brown     const char *name;
803f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
8049318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
805552f7358SJed Brown     PetscMPIInt rank, size;
806552f7358SJed Brown 
8079566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
8089566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
8099566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
8109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
8129566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
8139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
81463a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
81563a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
81663a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
81763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
8189566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
81963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
820552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
821552f7358SJed Brown       PetscInt dof, off, s;
822552f7358SJed Brown 
8239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
825552f7358SJed Brown       for (s = off; s < off+dof; ++s) {
82663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
827552f7358SJed Brown       }
828552f7358SJed Brown     }
8299566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
83063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
83163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
832552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
833552f7358SJed Brown       PetscInt dof, off, c;
834552f7358SJed Brown 
8359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
8369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
837552f7358SJed Brown       for (c = off; c < off+dof; ++c) {
83863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
839552f7358SJed Brown       }
840552f7358SJed Brown     }
8419566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
8429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8433d2e540fSStefano Zampini     if (coordSection && coordinates) {
84419ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
84519ad8254SMatthew G. Knepley       const PetscScalar *array;
84619ad8254SMatthew G. Knepley       PetscInt           Nf, Nc, pStart, pEnd, p;
84719ad8254SMatthew G. Knepley       PetscMPIInt        rank;
84819ad8254SMatthew G. Knepley       const char        *name;
84919ad8254SMatthew G. Knepley 
8509566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL));
8519566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
8529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
85363a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
8549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
8559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
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));
8629566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8639566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
86419ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
86519ad8254SMatthew G. Knepley         PetscInt dof, off;
86619ad8254SMatthew G. Knepley 
8679566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, p, &dof));
8689566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, p, &off));
86963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
8709566063dSJacob Faibussowitsch         PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
8719566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
87219ad8254SMatthew G. Knepley       }
8739566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
8749566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8759566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
8763d2e540fSStefano Zampini     }
8779566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
8789566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
8799318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
8809318fe57SMatthew G. Knepley       DMLabel     label;
8819318fe57SMatthew G. Knepley       PetscBool   isdepth;
8829318fe57SMatthew G. Knepley       const char *name;
8839318fe57SMatthew G. Knepley 
8849566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
8859566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
8869318fe57SMatthew G. Knepley       if (isdepth) continue;
8879566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
8889566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
8899318fe57SMatthew G. Knepley     }
890552f7358SJed Brown     if (size > 1) {
891552f7358SJed Brown       PetscSF sf;
892552f7358SJed Brown 
8939566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
8949566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
895552f7358SJed Brown     }
8969566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
897552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
8980588280cSMatthew G. Knepley     const char  *name, *color;
8990588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
9000588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
901fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
902552f7358SJed Brown     PetscReal    scale         = 2.0;
90378081901SStefano Zampini     PetscReal    tikzscale     = 1.0;
904b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers    = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
9050588280cSMatthew G. Knepley     double       tcoords[3];
906552f7358SJed Brown     PetscScalar *coords;
907b7f6ffafSMatthew G. Knepley     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
908552f7358SJed Brown     PetscMPIInt  rank, size;
9090588280cSMatthew G. Knepley     char         **names, **colors, **lcolors;
910b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
911fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
912fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
913552f7358SJed Brown 
9149566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
9169566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
9170588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
9180588280cSMatthew G. Knepley     numColors  = 10;
9190588280cSMatthew G. Knepley     numLColors = 10;
9209566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
9219566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
9229566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
9239566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
924b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
925b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d]  = PETSC_TRUE;
926b7f6ffafSMatthew G. Knepley     n = 4;
9279566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
9281dca8a05SBarry 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);
9299566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
9301dca8a05SBarry 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);
9319566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
9320588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
9339566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
9340588280cSMatthew G. Knepley     if (!useColors) {
9350588280cSMatthew G. Knepley       numColors = 3;
9369566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
9370588280cSMatthew G. Knepley     }
9389566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
9390588280cSMatthew G. Knepley     if (!useColors) {
9400588280cSMatthew G. Knepley       numLColors = 4;
9419566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
9420588280cSMatthew G. Knepley     }
9439566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
944b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
9459566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
9461dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
947202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
9489566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
949fe1cc32dSStefano Zampini 
950fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
9519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
955fe1cc32dSStefano Zampini     if (lflg) {
956fe1cc32dSStefano Zampini       DMLabel lbl;
957fe1cc32dSStefano Zampini 
9589566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
959fe1cc32dSStefano Zampini       if (lbl) {
960fe1cc32dSStefano Zampini         PetscInt val, defval;
961fe1cc32dSStefano Zampini 
9629566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
9639566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd-pStart, &wp));
964fe1cc32dSStefano Zampini         for (c = pStart;  c < pEnd; c++) {
965fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
966fe1cc32dSStefano Zampini           PetscInt  closureSize;
967fe1cc32dSStefano Zampini 
9689566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
969fe1cc32dSStefano Zampini           if (val == defval) continue;
970fe1cc32dSStefano Zampini 
9719566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
972fe1cc32dSStefano Zampini           for (p = 0; p < closureSize*2; p += 2) {
9739566063dSJacob Faibussowitsch             PetscCall(PetscBTSet(wp, closure[p] - pStart));
974fe1cc32dSStefano Zampini           }
9759566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
976fe1cc32dSStefano Zampini         }
977fe1cc32dSStefano Zampini       }
978fe1cc32dSStefano Zampini     }
979fe1cc32dSStefano Zampini 
9809566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
9819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
9829566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
9839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
9840588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
985552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
986552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
987552f7358SJed Brown \\usetikzlibrary{arrows}\n\
9885f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
9890588280cSMatthew G. Knepley     if (size > 1) {
9909566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
991770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
99263a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " :  ", "));
99363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p));
994770b213bSMatthew G Knepley       }
9959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
9960588280cSMatthew G. Knepley     }
997b7f6ffafSMatthew G. Knepley     if (drawHasse) {
998b7f6ffafSMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart));
999b7f6ffafSMatthew G. Knepley 
100063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
100163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1));
100263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart));
10039566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.));
100463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
100563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1));
10069566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.));
100763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart));
100863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
100963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1));
101063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart));
10119566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.));
1012b7f6ffafSMatthew G. Knepley     }
10139566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale));
1014fe1cc32dSStefano Zampini 
1015552f7358SJed Brown     /* Plot vertices */
10169566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
10179566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1018552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1019552f7358SJed Brown       PetscInt  off, dof, d;
10200588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1021552f7358SJed Brown 
1022fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
10239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
10249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
10259566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
102663a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof);
10270588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
10280588280cSMatthew G. Knepley         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1029c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
10300588280cSMatthew G. Knepley       }
10310588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
10320588280cSMatthew G. Knepley       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1033552f7358SJed Brown       for (d = 0; d < dof; ++d) {
10349566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
10359566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]));
1036552f7358SJed Brown       }
1037b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0%numColors];
1038b7f6ffafSMatthew G. Knepley       else           color = colors[rank%numColors];
10390588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
10400588280cSMatthew G. Knepley         PetscInt val;
10419566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
10420588280cSMatthew G. Knepley         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
10430588280cSMatthew G. Knepley       }
1044b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
104563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1046b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
104763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
1048b7f6ffafSMatthew G. Knepley       } else {
104963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
10500588280cSMatthew G. Knepley       }
1051552f7358SJed Brown     }
10529566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
10539566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1054b7f6ffafSMatthew G. Knepley     /* Plot edges */
1055b7f6ffafSMatthew G. Knepley     if (plotEdges) {
10569566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
10579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1058b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1059b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1060b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1061b7f6ffafSMatthew G. Knepley 
1062b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
10639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
106463a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
10659566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
10669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
10679566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
10689566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
10699566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1070b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1071b7f6ffafSMatthew G. Knepley           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
1072b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1073b7f6ffafSMatthew G. Knepley         }
1074b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1075b7f6ffafSMatthew G. Knepley         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1076b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
10779566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
10789566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1079b7f6ffafSMatthew G. Knepley         }
1080b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1%numColors];
1081b7f6ffafSMatthew G. Knepley         else           color = colors[rank%numColors];
1082b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1083b7f6ffafSMatthew G. Knepley           PetscInt val;
10849566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1085b7f6ffafSMatthew G. Knepley           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1086b7f6ffafSMatthew G. Knepley         }
108763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1088b7f6ffafSMatthew G. Knepley       }
10899566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
10909566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
10919566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1092b7f6ffafSMatthew G. Knepley     }
1093846a3e8bSMatthew G. Knepley     /* Plot cells */
1094b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1095846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1096846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1097846a3e8bSMatthew G. Knepley 
1098fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1099846a3e8bSMatthew G. Knepley         color = colors[rank%numColors];
1100846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1101846a3e8bSMatthew G. Knepley           PetscInt val;
11029566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1103846a3e8bSMatthew G. Knepley           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1104846a3e8bSMatthew G. Knepley         }
11059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
110663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1107846a3e8bSMatthew G. Knepley       }
1108846a3e8bSMatthew G. Knepley     } else {
1109b7f6ffafSMatthew G. Knepley        DMPolytopeType ct;
1110846a3e8bSMatthew G. Knepley 
1111b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1112b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1113fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
11149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
1115b7f6ffafSMatthew G. Knepley         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR ||
1116b7f6ffafSMatthew G. Knepley             ct == DM_POLYTOPE_TRI_PRISM_TENSOR ||
1117b7f6ffafSMatthew G. Knepley             ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1118b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1119b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1120b7f6ffafSMatthew G. Knepley 
11219566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
11229566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1123b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1124b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1125b7f6ffafSMatthew G. Knepley 
11269566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
112763a3b9bcSJacob 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));
1128b7f6ffafSMatthew G. Knepley           }
1129b7f6ffafSMatthew G. Knepley         } else {
1130b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1131b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1132b7f6ffafSMatthew G. Knepley 
11339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1134846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize*2; p += 2) {
1135846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1136846a3e8bSMatthew G. Knepley 
1137b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1138846a3e8bSMatthew G. Knepley           }
11399566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]));
1140b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1141b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v%Nv];
1142b7f6ffafSMatthew G. Knepley 
1143b7f6ffafSMatthew G. Knepley             if (v > 0) {
1144b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1145b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1146b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1147b7f6ffafSMatthew G. Knepley 
1148b7f6ffafSMatthew G. Knepley                 endpoints[0] = closure[v-1]; endpoints[1] = vertex;
11499566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
115063a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
115163a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
11529566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
1153b7f6ffafSMatthew G. Knepley               } else {
11549566063dSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1155b7f6ffafSMatthew G. Knepley               }
1156b7f6ffafSMatthew G. Knepley             }
115763a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1158b7f6ffafSMatthew G. Knepley           }
11599566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
11609566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1161846a3e8bSMatthew G. Knepley         }
1162846a3e8bSMatthew G. Knepley       }
1163b7f6ffafSMatthew G. Knepley     }
11649566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
1165846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1166846a3e8bSMatthew G. Knepley       double    ccoords[3] = {0.0, 0.0, 0.0};
1167846a3e8bSMatthew G. Knepley       PetscBool isLabeled  = PETSC_FALSE;
1168846a3e8bSMatthew G. Knepley       PetscInt *closure    = NULL;
1169846a3e8bSMatthew G. Knepley       PetscInt  closureSize, dof, d, n = 0;
1170846a3e8bSMatthew G. Knepley 
1171fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
11729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
11739566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1174846a3e8bSMatthew G. Knepley       for (p = 0; p < closureSize*2; p += 2) {
1175846a3e8bSMatthew G. Knepley         const PetscInt point = closure[p];
1176846a3e8bSMatthew G. Knepley         PetscInt       off;
1177846a3e8bSMatthew G. Knepley 
1178846a3e8bSMatthew G. Knepley         if ((point < vStart) || (point >= vEnd)) continue;
11799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, point, &dof));
11809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, point, &off));
1181846a3e8bSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1182846a3e8bSMatthew G. Knepley           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1183846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1184846a3e8bSMatthew G. Knepley         }
1185846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1186846a3e8bSMatthew G. Knepley         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1187846a3e8bSMatthew G. Knepley         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
1188846a3e8bSMatthew G. Knepley         ++n;
1189846a3e8bSMatthew G. Knepley       }
1190846a3e8bSMatthew G. Knepley       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
11919566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1192846a3e8bSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
11939566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
11949566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]));
1195846a3e8bSMatthew G. Knepley       }
1196b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth%numColors];
1197b7f6ffafSMatthew G. Knepley       else           color = colors[rank%numColors];
1198846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1199846a3e8bSMatthew G. Knepley         PetscInt val;
12009566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
1201846a3e8bSMatthew G. Knepley         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1202846a3e8bSMatthew G. Knepley       }
1203b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
120463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1205b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
120663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
1207b7f6ffafSMatthew G. Knepley       } else {
120863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1209846a3e8bSMatthew G. Knepley       }
1210846a3e8bSMatthew G. Knepley     }
12119566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
1212b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1213b7f6ffafSMatthew G. Knepley       color = colors[depth%numColors];
12149566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
12159566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
12169566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12179566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
12189566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1219552f7358SJed Brown 
1220b7f6ffafSMatthew G. Knepley       color = colors[1%numColors];
12219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
12229566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
12239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12249566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
12259566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1226b7f6ffafSMatthew G. Knepley 
1227b7f6ffafSMatthew G. Knepley       color = colors[0%numColors];
12289566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
12299566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
12309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
12319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
12329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1233b7f6ffafSMatthew G. Knepley 
1234b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1235b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1236b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1237b7f6ffafSMatthew G. Knepley 
12389566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
12399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1240b7f6ffafSMatthew G. Knepley         for (cp = 0; cp < coneSize; ++cp) {
124163a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1242552f7358SJed Brown         }
12430588280cSMatthew G. Knepley       }
12440588280cSMatthew G. Knepley     }
12459566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
12469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
12479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
124863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
12499566063dSJacob Faibussowitsch     for (l = 0; l < numLabels;  ++l) PetscCall(PetscFree(names[l]));
12509566063dSJacob Faibussowitsch     for (c = 0; c < numColors;  ++c) PetscCall(PetscFree(colors[c]));
12519566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
12529566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
12539566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
12540f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
12550f7d6e4aSStefano Zampini     Vec                    cown,acown;
12560f7d6e4aSStefano Zampini     VecScatter             sct;
12570f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
12580f7d6e4aSStefano Zampini     IS                     gid,acis;
12590f7d6e4aSStefano Zampini     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
12600f7d6e4aSStefano Zampini     MPI_Group              ggroup,ngroup;
12610f7d6e4aSStefano Zampini     PetscScalar            *array,nid;
12620f7d6e4aSStefano Zampini     const PetscInt         *idxs;
12630f7d6e4aSStefano Zampini     PetscInt               *idxs2,*start,*adjacency,*work;
12640f7d6e4aSStefano Zampini     PetscInt64             lm[3],gm[3];
12650f7d6e4aSStefano Zampini     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
12660f7d6e4aSStefano Zampini     PetscMPIInt            d1,d2,rank;
12670f7d6e4aSStefano Zampini 
12689566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
12699566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm,&rank));
1270b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
12719566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm));
12720f7d6e4aSStefano Zampini #endif
12730f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
12749566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm,&ggroup));
12759566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm,&ngroup));
12760f7d6e4aSStefano Zampini       d1   = 0;
12779566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2));
12780f7d6e4aSStefano Zampini       nid  = d2;
12799566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
12809566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
12819566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
12820f7d6e4aSStefano Zampini     } else nid = 0.0;
12830f7d6e4aSStefano Zampini 
12840f7d6e4aSStefano Zampini     /* Get connectivity */
12859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight));
12869566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid));
12870f7d6e4aSStefano Zampini 
12880f7d6e4aSStefano Zampini     /* filter overlapped local cells */
12899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd));
12909566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid,&idxs));
12919566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid,&cum));
12929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum,&idxs2));
12930f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
12940f7d6e4aSStefano Zampini       if (idxs[c-cStart] < 0) continue;
12950f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c-cStart];
12960f7d6e4aSStefano Zampini     }
12979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid,&idxs));
129863a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum);
12999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13009566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid));
13010f7d6e4aSStefano Zampini 
13020f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
13039566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis));
13049566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown));
13059566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown));
13069566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown,&array));
13070f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
13089566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown,&array));
13099566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct));
13109566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD));
13119566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD));
13129566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
13139566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
13149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
13150f7d6e4aSStefano Zampini 
13160f7d6e4aSStefano Zampini     /* compute edgeCut */
13170f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
13189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum,&work));
13199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l));
13209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH));
13219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
13229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown,&array));
13230f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
13240f7d6e4aSStefano Zampini       PetscInt totl;
13250f7d6e4aSStefano Zampini 
13260f7d6e4aSStefano Zampini       totl = start[c+1]-start[c];
13279566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work));
13280f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
13290f7d6e4aSStefano Zampini         if (work[i] < 0) {
13300f7d6e4aSStefano Zampini           ect  += 1;
13310f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
13320f7d6e4aSStefano Zampini         }
13330f7d6e4aSStefano Zampini       }
13340f7d6e4aSStefano Zampini     }
13359566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
13369566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown,&array));
13370f7d6e4aSStefano Zampini     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
13380f7d6e4aSStefano Zampini     lm[1] = -numVertices;
13391c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm));
134063a3b9bcSJacob 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]));
13410f7d6e4aSStefano Zampini     lm[0] = ect; /* edgeCut */
13420f7d6e4aSStefano Zampini     lm[1] = ectn; /* node-aware edgeCut */
13430f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
13441c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm));
134563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2]));
1346b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
134763a3b9bcSJacob 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.));
13480f7d6e4aSStefano Zampini #else
134963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0));
13500f7d6e4aSStefano Zampini #endif
13519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
13529566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
13539566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
13549566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1355552f7358SJed Brown   } else {
1356412e9a14SMatthew G. Knepley     const char    *name;
1357d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1358412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1359d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1360ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
13619318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1362412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1363412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1364552f7358SJed Brown 
13659566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
13669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
13679566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
13689566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
13699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
13709566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
137163a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
137263a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
137363a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
13749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
13751c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
13769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd));
1377d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
13789566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
13799566063dSJacob Faibussowitsch     else                PetscCall(PetscCalloc3(3,    &sizes, 3,    &hybsizes, 3,    &ghostsizes));
1380412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1381412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1382412e9a14SMatthew G. Knepley 
13839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
13849566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1385412e9a14SMatthew G. Knepley       ict  = ct0;
13869566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1387412e9a14SMatthew G. Knepley       ct0  = (DMPolytopeType) ict;
1388412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1389412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1390412e9a14SMatthew G. Knepley 
13919566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1392412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1393412e9a14SMatthew G. Knepley         else           ++Nc[1];
1394412e9a14SMatthew G. Knepley       }
1395ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
13969566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm));
13979566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
13989566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
139963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1400834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1401dd400576SPatrick Sanan           if (rank == 0) {
140263a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p]));
140363a3b9bcSJacob Faibussowitsch             if (hybsizes[p]   > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
140463a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1405834065abSMatthew G. Knepley           }
1406cbb7f117SMark Adams         }
1407ca7bf7eeSMatthew G. Knepley       } else {
1408ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1409ca7bf7eeSMatthew G. Knepley 
1410ca7bf7eeSMatthew G. Knepley         locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1];
14119566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1412ca7bf7eeSMatthew G. Knepley         locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1];
14139566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1414ca7bf7eeSMatthew G. Knepley         if (d == depth) {
1415ca7bf7eeSMatthew G. Knepley           locMinMax[0] = gcNum; locMinMax[1] = gcNum;
14169566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1417ca7bf7eeSMatthew G. Knepley         }
141863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
14199566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
14209566063dSJacob Faibussowitsch         if (hybsizes[0]   > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
14219566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1422ca7bf7eeSMatthew G. Knepley       }
14239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1424552f7358SJed Brown     }
14259566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
14269318fe57SMatthew G. Knepley     {
14279318fe57SMatthew G. Knepley       const PetscReal      *maxCell;
14289318fe57SMatthew G. Knepley       const PetscReal      *L;
14299318fe57SMatthew G. Knepley       const DMBoundaryType *bd;
14309318fe57SMatthew G. Knepley       PetscBool             per, localized;
14319318fe57SMatthew G. Knepley 
14329566063dSJacob Faibussowitsch       PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd));
14339566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
14349318fe57SMatthew G. Knepley       if (per) {
14359566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh ("));
14369566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
14379318fe57SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
14389566063dSJacob Faibussowitsch           if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
14399566063dSJacob Faibussowitsch           if (bd)    PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]));
14409318fe57SMatthew G. Knepley         }
14419566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized"));
14429566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
14439318fe57SMatthew G. Knepley       }
14449318fe57SMatthew G. Knepley     }
14459566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
14469566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1447a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1448a57dd577SMatthew G Knepley       DMLabel         label;
1449a57dd577SMatthew G Knepley       const char     *name;
1450a57dd577SMatthew G Knepley       IS              valueIS;
1451a57dd577SMatthew G Knepley       const PetscInt *values;
1452a57dd577SMatthew G Knepley       PetscInt        numValues, v;
1453a57dd577SMatthew G Knepley 
14549566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
14559566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
14569566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
145763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
14589566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValueIS(label, &valueIS));
14599566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(valueIS, &values));
14609566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1461a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1462a57dd577SMatthew G Knepley         PetscInt size;
1463a57dd577SMatthew G Knepley 
14649566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
14659566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
146663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1467a57dd577SMatthew G Knepley       }
14689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
14699566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
14709566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(valueIS, &values));
14719566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&valueIS));
1472a57dd577SMatthew G Knepley     }
1473c1cad2e7SMatthew G. Knepley     {
1474c1cad2e7SMatthew G. Knepley       char    **labelNames;
1475c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1476c1cad2e7SMatthew G. Knepley       PetscBool flg;
1477c1cad2e7SMatthew G. Knepley 
14789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
14799566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1480c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1481c1cad2e7SMatthew G. Knepley         DMLabel label;
1482c1cad2e7SMatthew G. Knepley 
14839566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1484c1cad2e7SMatthew G. Knepley         if (flg) {
14859566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
14869566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1487c1cad2e7SMatthew G. Knepley         }
14889566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1489c1cad2e7SMatthew G. Knepley       }
14909566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1491c1cad2e7SMatthew G. Knepley     }
149234aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
149334aa8a36SMatthew G. Knepley     if (dm->Nf) {
149434aa8a36SMatthew G. Knepley       PetscInt f;
149534aa8a36SMatthew G. Knepley 
149634aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
149734aa8a36SMatthew G. Knepley         const char *name;
149834aa8a36SMatthew G. Knepley 
14999566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
15009566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
15019566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
15029566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
150334aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
15049566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
15059566063dSJacob Faibussowitsch           else                            PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
150634aa8a36SMatthew G. Knepley         } else {
15079566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
15089566063dSJacob Faibussowitsch           else                            PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
150934aa8a36SMatthew G. Knepley         }
15109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
151134aa8a36SMatthew G. Knepley       }
151234aa8a36SMatthew G. Knepley     }
15139566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
15148e7ff633SMatthew G. Knepley     if (cdm) {
15159566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
15169566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
15179566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
15188e7ff633SMatthew G. Knepley     }
1519552f7358SJed Brown   }
1520552f7358SJed Brown   PetscFunctionReturn(0);
1521552f7358SJed Brown }
1522552f7358SJed Brown 
1523e5c487bfSMatthew G. Knepley static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1524e5c487bfSMatthew G. Knepley {
1525e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1526e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1527a12d352dSMatthew G. Knepley   PetscInt       cdim;
1528e5c487bfSMatthew G. Knepley 
1529e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
15309566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
15319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
15329566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1533e5c487bfSMatthew G. Knepley   switch (ct) {
1534a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1535a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1536a12d352dSMatthew G. Knepley     switch (cdim) {
1537a12d352dSMatthew G. Knepley     case 1:
1538a12d352dSMatthew G. Knepley     {
1539a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1540a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1541a12d352dSMatthew G. Knepley 
15429566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y,    PetscRealPart(coords[1]), y,    PETSC_DRAW_BLACK));
15439566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK));
15449566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK));
1545a12d352dSMatthew G. Knepley     }
1546a12d352dSMatthew G. Knepley     break;
1547a12d352dSMatthew G. Knepley     case 2:
1548a12d352dSMatthew G. Knepley     {
1549a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1550a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1551a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1/PetscSqrtReal(dx*dx + dy*dy);
1552a12d352dSMatthew G. Knepley 
15539566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
15549566063dSJacob 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));
15559566063dSJacob 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));
1556a12d352dSMatthew G. Knepley     }
1557a12d352dSMatthew G. Knepley     break;
155863a3b9bcSJacob Faibussowitsch     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1559a12d352dSMatthew G. Knepley     }
1560a12d352dSMatthew G. Knepley     break;
1561e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
15629566063dSJacob Faibussowitsch     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1563e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1564e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
15655f80ce2aSJacob Faibussowitsch                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
15669566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
15679566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
15689566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1569e5c487bfSMatthew G. Knepley     break;
1570e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
15719566063dSJacob Faibussowitsch     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1572e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1573e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
15745f80ce2aSJacob Faibussowitsch                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
15759566063dSJacob Faibussowitsch     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1576e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1577e5c487bfSMatthew G. Knepley                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
15785f80ce2aSJacob Faibussowitsch                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2));
15799566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
15809566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
15819566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
15829566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1583e5c487bfSMatthew G. Knepley     break;
158498921bdaSJacob Faibussowitsch   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1585e5c487bfSMatthew G. Knepley   }
1586e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
1587e5c487bfSMatthew G. Knepley }
1588e5c487bfSMatthew G. Knepley 
1589e5c487bfSMatthew G. Knepley static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1590e5c487bfSMatthew G. Knepley {
1591e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1592e5c487bfSMatthew G. Knepley   PetscReal      centroid[2] = {0., 0.};
1593e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1594e5c487bfSMatthew G. Knepley   PetscInt       fillColor, v, e, d;
1595e5c487bfSMatthew G. Knepley 
1596e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
15979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
15989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1599e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1600e5c487bfSMatthew G. Knepley   switch (ct) {
1601e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
1602e5c487bfSMatthew G. Knepley     {
1603e5c487bfSMatthew G. Knepley       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1604e5c487bfSMatthew G. Knepley 
1605e5c487bfSMatthew G. Knepley       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1606e5c487bfSMatthew G. Knepley       for (e = 0; e < 3; ++e) {
1607e5c487bfSMatthew G. Knepley         refCoords[0] = refVertices[e*2+0];
1608e5c487bfSMatthew G. Knepley         refCoords[1] = refVertices[e*2+1];
1609e5c487bfSMatthew G. Knepley         for (d = 1; d <= edgeDiv; ++d) {
1610e5c487bfSMatthew G. Knepley           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1611e5c487bfSMatthew G. Knepley           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1612e5c487bfSMatthew G. Knepley         }
16139566063dSJacob Faibussowitsch         PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords));
1614e5c487bfSMatthew G. Knepley         for (d = 0; d < edgeDiv; ++d) {
16159566063dSJacob 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));
16169566063dSJacob 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));
1617e5c487bfSMatthew G. Knepley         }
1618e5c487bfSMatthew G. Knepley       }
1619e5c487bfSMatthew G. Knepley     }
1620e5c487bfSMatthew G. Knepley     break;
162198921bdaSJacob Faibussowitsch   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1622e5c487bfSMatthew G. Knepley   }
1623e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
1624e5c487bfSMatthew G. Knepley }
1625e5c487bfSMatthew G. Knepley 
16267cd05799SMatthew G. Knepley static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1627e412dcbdSMatthew G. Knepley {
1628e412dcbdSMatthew G. Knepley   PetscDraw          draw;
1629e412dcbdSMatthew G. Knepley   DM                 cdm;
1630e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
1631e412dcbdSMatthew G. Knepley   Vec                coordinates;
1632e412dcbdSMatthew G. Knepley   const PetscScalar *coords;
163329494db1SLisandro Dalcin   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1634e5c487bfSMatthew G. Knepley   PetscReal         *refCoords, *edgeCoords;
1635e5c487bfSMatthew G. Knepley   PetscBool          isnull, drawAffine = PETSC_TRUE;
1636e5c487bfSMatthew G. Knepley   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1637e412dcbdSMatthew G. Knepley 
1638e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
16399566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
164063a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
16419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
16429566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords));
16439566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
16449566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
16459566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
16469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
16479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1648e412dcbdSMatthew G. Knepley 
16499566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
16509566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
1651e412dcbdSMatthew G. Knepley   if (isnull) PetscFunctionReturn(0);
16529566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1653e412dcbdSMatthew G. Knepley 
16549566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
16559566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
1656e412dcbdSMatthew G. Knepley   for (c = 0; c < N; c += dim) {
16570c81f2a8SMatthew G. Knepley     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
16580c81f2a8SMatthew G. Knepley     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1659e412dcbdSMatthew G. Knepley   }
16609566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
16611c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm)));
16621c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm)));
16639566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
16649566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1665e412dcbdSMatthew G. Knepley 
1666cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1667cf3064d3SMatthew G. Knepley     PetscScalar *coords = NULL;
1668ba2698f1SMatthew G. Knepley     PetscInt     numCoords;
1669cf3064d3SMatthew G. Knepley 
16709566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords));
1671e5c487bfSMatthew G. Knepley     if (drawAffine) {
16729566063dSJacob Faibussowitsch       PetscCall(DMPlexDrawCell(dm, draw, c, coords));
1673e5c487bfSMatthew G. Knepley     } else {
16749566063dSJacob Faibussowitsch       PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1675cf3064d3SMatthew G. Knepley     }
16769566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords));
1677cf3064d3SMatthew G. Knepley   }
16789566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
16799566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
16809566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
16819566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
1682e412dcbdSMatthew G. Knepley   PetscFunctionReturn(0);
1683e412dcbdSMatthew G. Knepley }
1684e412dcbdSMatthew G. Knepley 
16851e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
16861e50132fSMatthew G. Knepley #include <exodusII.h>
16876823f3c5SBlaise Bourdin #include <petscviewerexodusii.h>
16881e50132fSMatthew G. Knepley #endif
16891e50132fSMatthew G. Knepley 
1690552f7358SJed Brown PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1691552f7358SJed Brown {
16921e50132fSMatthew G. Knepley   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1693002a2709SMatthew G. Knepley   char           name[PETSC_MAX_PATH_LEN];
1694552f7358SJed Brown 
1695552f7358SJed Brown   PetscFunctionBegin;
1696552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1697552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
16989566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii));
16999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk));
17009566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5));
17019566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw));
17029566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis));
17039566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus));
1704552f7358SJed Brown   if (iascii) {
17058135c375SStefano Zampini     PetscViewerFormat format;
17069566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
17078135c375SStefano Zampini     if (format == PETSC_VIEWER_ASCII_GLVIS) {
17089566063dSJacob Faibussowitsch       PetscCall(DMPlexView_GLVis(dm, viewer));
17098135c375SStefano Zampini     } else {
17109566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(dm, viewer));
17118135c375SStefano Zampini     }
1712c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1713c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
17149566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1715c6ccd67eSMatthew G. Knepley #else
1716c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1717552f7358SJed Brown #endif
1718e412dcbdSMatthew G. Knepley   } else if (isvtk) {
17199566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer));
1720e412dcbdSMatthew G. Knepley   } else if (isdraw) {
17219566063dSJacob Faibussowitsch     PetscCall(DMPlexView_Draw(dm, viewer));
17228135c375SStefano Zampini   } else if (isglvis) {
17239566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
17241e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
17251e50132fSMatthew G. Knepley   } else if (isexodus) {
17266823f3c5SBlaise Bourdin /*
17276823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
17286823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
17296823f3c5SBlaise Bourdin       with ID 1, containig all cells.
17306823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
17316823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
17326823f3c5SBlaise Bourdin     */
17336823f3c5SBlaise Bourdin     PetscInt numCS;
17349566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS));
17356823f3c5SBlaise Bourdin     if (!numCS) {
17361e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
17379566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
17389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
17399566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
17406823f3c5SBlaise Bourdin     }
17419566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
17421e50132fSMatthew G. Knepley #endif
174362201deeSVaclav Hapla   } else {
174498921bdaSJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1745fcf6c8fdSToby Isaac   }
1746cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
17479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg));
1748cb3ba0daSMatthew G. Knepley   if (flg) {
1749cb3ba0daSMatthew G. Knepley     Vec ranks;
17509566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
17519566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
17529566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
1753cb3ba0daSMatthew G. Knepley   }
1754002a2709SMatthew G. Knepley   /* Optionally view a label */
17559566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1756002a2709SMatthew G. Knepley   if (flg) {
1757002a2709SMatthew G. Knepley     DMLabel label;
1758002a2709SMatthew G. Knepley     Vec     val;
1759002a2709SMatthew G. Knepley 
17609566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
176128b400f6SJacob Faibussowitsch     PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
17629566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
17639566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
17649566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
1765002a2709SMatthew G. Knepley   }
1766552f7358SJed Brown   PetscFunctionReturn(0);
1767552f7358SJed Brown }
1768552f7358SJed Brown 
17697f96f51bSksagiyam /*@
17707f96f51bSksagiyam   DMPlexTopologyView - Saves a DMPlex topology into a file
17717f96f51bSksagiyam 
17727f96f51bSksagiyam   Collective on DM
17737f96f51bSksagiyam 
17747f96f51bSksagiyam   Input Parameters:
17757f96f51bSksagiyam + dm     - The DM whose topology is to be saved
17767f96f51bSksagiyam - viewer - The PetscViewer for saving
17777f96f51bSksagiyam 
17787f96f51bSksagiyam   Level: advanced
17797f96f51bSksagiyam 
1780db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`
17817f96f51bSksagiyam @*/
17827f96f51bSksagiyam PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
17837f96f51bSksagiyam {
17847f96f51bSksagiyam   PetscBool      ishdf5;
17857f96f51bSksagiyam 
17867f96f51bSksagiyam   PetscFunctionBegin;
17877f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
17887f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
17899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
17909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0));
17917f96f51bSksagiyam   if (ishdf5) {
17927f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
17937f96f51bSksagiyam     PetscViewerFormat format;
17949566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
17957f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
17967f96f51bSksagiyam       IS globalPointNumbering;
17977f96f51bSksagiyam 
17989566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
17999566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
18009566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
180198921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
18027f96f51bSksagiyam #else
18037f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
18047f96f51bSksagiyam #endif
18057f96f51bSksagiyam   }
18069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0));
18077f96f51bSksagiyam   PetscFunctionReturn(0);
18087f96f51bSksagiyam }
18097f96f51bSksagiyam 
181077b8e257Sksagiyam /*@
181177b8e257Sksagiyam   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
181277b8e257Sksagiyam 
181377b8e257Sksagiyam   Collective on DM
181477b8e257Sksagiyam 
181577b8e257Sksagiyam   Input Parameters:
181677b8e257Sksagiyam + dm     - The DM whose coordinates are to be saved
181777b8e257Sksagiyam - viewer - The PetscViewer for saving
181877b8e257Sksagiyam 
181977b8e257Sksagiyam   Level: advanced
182077b8e257Sksagiyam 
1821db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`
182277b8e257Sksagiyam @*/
182377b8e257Sksagiyam PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
182477b8e257Sksagiyam {
182577b8e257Sksagiyam   PetscBool      ishdf5;
182677b8e257Sksagiyam 
182777b8e257Sksagiyam   PetscFunctionBegin;
182877b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
182977b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
18319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0));
183277b8e257Sksagiyam   if (ishdf5) {
183377b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
183477b8e257Sksagiyam     PetscViewerFormat format;
18359566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
183677b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18379566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
183898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
183977b8e257Sksagiyam #else
184077b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
184177b8e257Sksagiyam #endif
184277b8e257Sksagiyam   }
18439566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0));
184477b8e257Sksagiyam   PetscFunctionReturn(0);
184577b8e257Sksagiyam }
184677b8e257Sksagiyam 
1847bd6565f1Sksagiyam /*@
1848bd6565f1Sksagiyam   DMPlexLabelsView - Saves DMPlex labels into a file
1849bd6565f1Sksagiyam 
1850bd6565f1Sksagiyam   Collective on DM
1851bd6565f1Sksagiyam 
1852bd6565f1Sksagiyam   Input Parameters:
1853bd6565f1Sksagiyam + dm     - The DM whose labels are to be saved
1854bd6565f1Sksagiyam - viewer - The PetscViewer for saving
1855bd6565f1Sksagiyam 
1856bd6565f1Sksagiyam   Level: advanced
1857bd6565f1Sksagiyam 
1858db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`
1859bd6565f1Sksagiyam @*/
1860bd6565f1Sksagiyam PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1861bd6565f1Sksagiyam {
1862bd6565f1Sksagiyam   PetscBool      ishdf5;
1863bd6565f1Sksagiyam 
1864bd6565f1Sksagiyam   PetscFunctionBegin;
1865bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1866bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
18679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
18689566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0));
1869bd6565f1Sksagiyam   if (ishdf5) {
1870bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
1871bd6565f1Sksagiyam     IS                globalPointNumbering;
1872bd6565f1Sksagiyam     PetscViewerFormat format;
1873bd6565f1Sksagiyam 
18749566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
1875bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
18769566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
18779566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
18789566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
187998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1880bd6565f1Sksagiyam #else
1881bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1882bd6565f1Sksagiyam #endif
1883bd6565f1Sksagiyam   }
18849566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0));
1885bd6565f1Sksagiyam   PetscFunctionReturn(0);
1886bd6565f1Sksagiyam }
1887bd6565f1Sksagiyam 
1888021affd3Sksagiyam /*@
1889021affd3Sksagiyam   DMPlexSectionView - Saves a section associated with a DMPlex
1890021affd3Sksagiyam 
1891021affd3Sksagiyam   Collective on DM
1892021affd3Sksagiyam 
1893021affd3Sksagiyam   Input Parameters:
1894021affd3Sksagiyam + dm         - The DM that contains the topology on which the section to be saved is defined
1895021affd3Sksagiyam . viewer     - The PetscViewer for saving
1896021affd3Sksagiyam - sectiondm  - The DM that contains the section to be saved
1897021affd3Sksagiyam 
1898021affd3Sksagiyam   Level: advanced
1899021affd3Sksagiyam 
1900021affd3Sksagiyam   Notes:
1901021affd3Sksagiyam   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.
1902021affd3Sksagiyam 
1903021affd3Sksagiyam   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.
1904021affd3Sksagiyam 
1905db781477SPatrick Sanan .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`
1906021affd3Sksagiyam @*/
1907021affd3Sksagiyam PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1908021affd3Sksagiyam {
1909021affd3Sksagiyam   PetscBool      ishdf5;
1910021affd3Sksagiyam 
1911021affd3Sksagiyam   PetscFunctionBegin;
1912021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1913021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1914021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
19159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
19169566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0));
1917021affd3Sksagiyam   if (ishdf5) {
1918021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
19199566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1920021affd3Sksagiyam #else
1921021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1922021affd3Sksagiyam #endif
1923021affd3Sksagiyam   }
19249566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0));
1925021affd3Sksagiyam   PetscFunctionReturn(0);
1926021affd3Sksagiyam }
1927021affd3Sksagiyam 
19283e97647fSksagiyam /*@
19293e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
19303e97647fSksagiyam 
19313e97647fSksagiyam   Collective on DM
19323e97647fSksagiyam 
19333e97647fSksagiyam   Input Parameters:
19343e97647fSksagiyam + dm        - The DM that represents the topology
19353e97647fSksagiyam . viewer    - The PetscViewer to save data with
19363e97647fSksagiyam . sectiondm - The DM that contains the global section on which vec is defined
19373e97647fSksagiyam - vec       - The global vector to be saved
19383e97647fSksagiyam 
19393e97647fSksagiyam   Level: advanced
19403e97647fSksagiyam 
19413e97647fSksagiyam   Notes:
19423e97647fSksagiyam   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.
19433e97647fSksagiyam 
19443e97647fSksagiyam   Typical calling sequence
19453e97647fSksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
19463e97647fSksagiyam $       DMSetType(dm, DMPLEX);
19473e97647fSksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
19483e97647fSksagiyam $       DMClone(dm, &sectiondm);
19493e97647fSksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
19503e97647fSksagiyam $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
19513e97647fSksagiyam $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
19523e97647fSksagiyam $       PetscSectionSetChart(section, pStart, pEnd);
19533e97647fSksagiyam $       PetscSectionSetUp(section);
19543e97647fSksagiyam $       DMSetLocalSection(sectiondm, section);
19553e97647fSksagiyam $       PetscSectionDestroy(&section);
19563e97647fSksagiyam $       DMGetGlobalVector(sectiondm, &vec);
19573e97647fSksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
19583e97647fSksagiyam $       DMPlexTopologyView(dm, viewer);
19593e97647fSksagiyam $       DMPlexSectionView(dm, viewer, sectiondm);
19603e97647fSksagiyam $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
19613e97647fSksagiyam $       DMRestoreGlobalVector(sectiondm, &vec);
19623e97647fSksagiyam $       DMDestroy(&sectiondm);
19633e97647fSksagiyam $       DMDestroy(&dm);
19643e97647fSksagiyam 
1965db781477SPatrick Sanan .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
19663e97647fSksagiyam @*/
19673e97647fSksagiyam PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
19683e97647fSksagiyam {
19693e97647fSksagiyam   PetscBool       ishdf5;
19703e97647fSksagiyam 
19713e97647fSksagiyam   PetscFunctionBegin;
19723e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19733e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19743e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
19753e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
19763e97647fSksagiyam   /* Check consistency */
19773e97647fSksagiyam   {
19783e97647fSksagiyam     PetscSection  section;
19793e97647fSksagiyam     PetscBool     includesConstraints;
19803e97647fSksagiyam     PetscInt      m, m1;
19813e97647fSksagiyam 
19829566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
19839566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
19849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
19859566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
19869566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
198763a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
19883e97647fSksagiyam   }
19899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0));
19913e97647fSksagiyam   if (ishdf5) {
19923e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
19939566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
19943e97647fSksagiyam #else
19953e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
19963e97647fSksagiyam #endif
19973e97647fSksagiyam   }
19989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0));
19993e97647fSksagiyam   PetscFunctionReturn(0);
20003e97647fSksagiyam }
20013e97647fSksagiyam 
20023e97647fSksagiyam /*@
20033e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
20043e97647fSksagiyam 
20053e97647fSksagiyam   Collective on DM
20063e97647fSksagiyam 
20073e97647fSksagiyam   Input Parameters:
20083e97647fSksagiyam + dm        - The DM that represents the topology
20093e97647fSksagiyam . viewer    - The PetscViewer to save data with
20103e97647fSksagiyam . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
20113e97647fSksagiyam - vec       - The local vector to be saved
20123e97647fSksagiyam 
20133e97647fSksagiyam   Level: advanced
20143e97647fSksagiyam 
20153e97647fSksagiyam   Notes:
20163e97647fSksagiyam   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.
20173e97647fSksagiyam 
20183e97647fSksagiyam   Typical calling sequence
20193e97647fSksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
20203e97647fSksagiyam $       DMSetType(dm, DMPLEX);
20213e97647fSksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
20223e97647fSksagiyam $       DMClone(dm, &sectiondm);
20233e97647fSksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
20243e97647fSksagiyam $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
20253e97647fSksagiyam $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
20263e97647fSksagiyam $       PetscSectionSetChart(section, pStart, pEnd);
20273e97647fSksagiyam $       PetscSectionSetUp(section);
20283e97647fSksagiyam $       DMSetLocalSection(sectiondm, section);
20293e97647fSksagiyam $       DMGetLocalVector(sectiondm, &vec);
20303e97647fSksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
20313e97647fSksagiyam $       DMPlexTopologyView(dm, viewer);
20323e97647fSksagiyam $       DMPlexSectionView(dm, viewer, sectiondm);
20333e97647fSksagiyam $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
20343e97647fSksagiyam $       DMRestoreLocalVector(sectiondm, &vec);
20353e97647fSksagiyam $       DMDestroy(&sectiondm);
20363e97647fSksagiyam $       DMDestroy(&dm);
20373e97647fSksagiyam 
2038db781477SPatrick Sanan .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
20393e97647fSksagiyam @*/
20403e97647fSksagiyam PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
20413e97647fSksagiyam {
20423e97647fSksagiyam   PetscBool       ishdf5;
20433e97647fSksagiyam 
20443e97647fSksagiyam   PetscFunctionBegin;
20453e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20463e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20473e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
20483e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
20493e97647fSksagiyam   /* Check consistency */
20503e97647fSksagiyam   {
20513e97647fSksagiyam     PetscSection  section;
20523e97647fSksagiyam     PetscBool     includesConstraints;
20533e97647fSksagiyam     PetscInt      m, m1;
20543e97647fSksagiyam 
20559566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
20569566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
20579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
20589566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
20599566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
206063a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
20613e97647fSksagiyam   }
20629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20639566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0));
20643e97647fSksagiyam   if (ishdf5) {
20653e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
20669566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
20673e97647fSksagiyam #else
20683e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20693e97647fSksagiyam #endif
20703e97647fSksagiyam   }
20719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0));
20723e97647fSksagiyam   PetscFunctionReturn(0);
20733e97647fSksagiyam }
20743e97647fSksagiyam 
20752c40f234SMatthew G. Knepley PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
20762c40f234SMatthew G. Knepley {
2077d4f5a9a0SVaclav Hapla   PetscBool      ishdf5;
20782c40f234SMatthew G. Knepley 
20792c40f234SMatthew G. Knepley   PetscFunctionBegin;
20802c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20812c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20829566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5));
2083d4f5a9a0SVaclav Hapla   if (ishdf5) {
20842c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
20859c48423bSVaclav Hapla     PetscViewerFormat format;
20869566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20879c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
20889566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2089509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20909566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
209198921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2092b458e8f1SJose E. Roman     PetscFunctionReturn(0);
20932c40f234SMatthew G. Knepley #else
20942c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2095552f7358SJed Brown #endif
209698921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2097552f7358SJed Brown }
2098552f7358SJed Brown 
2099ea8e1828Sksagiyam /*@
2100ea8e1828Sksagiyam   DMPlexTopologyLoad - Loads a topology into a DMPlex
2101ea8e1828Sksagiyam 
2102ea8e1828Sksagiyam   Collective on DM
2103ea8e1828Sksagiyam 
2104ea8e1828Sksagiyam   Input Parameters:
2105ea8e1828Sksagiyam + dm     - The DM into which the topology is loaded
2106ea8e1828Sksagiyam - viewer - The PetscViewer for the saved topology
2107ea8e1828Sksagiyam 
2108dec9e869Sksagiyam   Output Parameters:
2109f84dd6b4Sksagiyam . 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
2110dec9e869Sksagiyam 
2111ea8e1828Sksagiyam   Level: advanced
2112ea8e1828Sksagiyam 
2113db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
2114ea8e1828Sksagiyam @*/
2115f84dd6b4Sksagiyam PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2116ea8e1828Sksagiyam {
2117ea8e1828Sksagiyam   PetscBool      ishdf5;
2118ea8e1828Sksagiyam 
2119ea8e1828Sksagiyam   PetscFunctionBegin;
2120ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2121ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2122f84dd6b4Sksagiyam   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
21239566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
21249566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0));
2125ea8e1828Sksagiyam   if (ishdf5) {
2126ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2127ea8e1828Sksagiyam     PetscViewerFormat format;
21289566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2129ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21309566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
213198921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2132ea8e1828Sksagiyam #else
2133ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2134ea8e1828Sksagiyam #endif
2135ea8e1828Sksagiyam   }
21369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0));
2137ea8e1828Sksagiyam   PetscFunctionReturn(0);
2138ea8e1828Sksagiyam }
2139ea8e1828Sksagiyam 
21403e701f1cSksagiyam /*@
21413e701f1cSksagiyam   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
21423e701f1cSksagiyam 
21433e701f1cSksagiyam   Collective on DM
21443e701f1cSksagiyam 
21453e701f1cSksagiyam   Input Parameters:
21463e701f1cSksagiyam + dm     - The DM into which the coordinates are loaded
2147c9ad657eSksagiyam . viewer - The PetscViewer for the saved coordinates
2148c9ad657eSksagiyam - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
21493e701f1cSksagiyam 
21503e701f1cSksagiyam   Level: advanced
21513e701f1cSksagiyam 
2152db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
21533e701f1cSksagiyam @*/
2154c9ad657eSksagiyam PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
21553e701f1cSksagiyam {
21563e701f1cSksagiyam   PetscBool      ishdf5;
21573e701f1cSksagiyam 
21583e701f1cSksagiyam   PetscFunctionBegin;
21593e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21603e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2161c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
21629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
21639566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0));
21643e701f1cSksagiyam   if (ishdf5) {
21653e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
21663e701f1cSksagiyam     PetscViewerFormat format;
21679566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
21683e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21699566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
217098921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
21713e701f1cSksagiyam #else
21723e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
21733e701f1cSksagiyam #endif
21743e701f1cSksagiyam   }
21759566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0));
21763e701f1cSksagiyam   PetscFunctionReturn(0);
21773e701f1cSksagiyam }
21783e701f1cSksagiyam 
2179b08ad5deSksagiyam /*@
2180b08ad5deSksagiyam   DMPlexLabelsLoad - Loads labels into a DMPlex
2181b08ad5deSksagiyam 
2182b08ad5deSksagiyam   Collective on DM
2183b08ad5deSksagiyam 
2184b08ad5deSksagiyam   Input Parameters:
2185b08ad5deSksagiyam + dm     - The DM into which the labels are loaded
2186e6368b79SVaclav Hapla . viewer - The PetscViewer for the saved labels
2187e6368b79SVaclav Hapla - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2188b08ad5deSksagiyam 
2189b08ad5deSksagiyam   Level: advanced
2190b08ad5deSksagiyam 
2191e6368b79SVaclav Hapla   Notes:
2192e6368b79SVaclav Hapla   The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs.
2193e6368b79SVaclav Hapla 
2194db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`
2195b08ad5deSksagiyam @*/
2196e6368b79SVaclav Hapla PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2197b08ad5deSksagiyam {
2198b08ad5deSksagiyam   PetscBool      ishdf5;
2199b08ad5deSksagiyam 
2200b08ad5deSksagiyam   PetscFunctionBegin;
2201b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2202b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2203e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
22049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
22059566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0));
2206b08ad5deSksagiyam   if (ishdf5) {
2207b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2208b08ad5deSksagiyam     PetscViewerFormat format;
2209b08ad5deSksagiyam 
22109566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2211b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
22129566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
221398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2214b08ad5deSksagiyam #else
2215b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2216b08ad5deSksagiyam #endif
2217b08ad5deSksagiyam   }
22189566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0));
2219b08ad5deSksagiyam   PetscFunctionReturn(0);
2220b08ad5deSksagiyam }
2221b08ad5deSksagiyam 
2222f84dd6b4Sksagiyam /*@
2223f84dd6b4Sksagiyam   DMPlexSectionLoad - Loads section into a DMPlex
2224f84dd6b4Sksagiyam 
2225f84dd6b4Sksagiyam   Collective on DM
2226f84dd6b4Sksagiyam 
2227f84dd6b4Sksagiyam   Input Parameters:
2228f84dd6b4Sksagiyam + dm          - The DM that represents the topology
2229f84dd6b4Sksagiyam . viewer      - The PetscViewer that represents the on-disk section (sectionA)
2230f84dd6b4Sksagiyam . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2231f84dd6b4Sksagiyam - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2232f84dd6b4Sksagiyam 
2233f84dd6b4Sksagiyam   Output Parameters
2234f84dd6b4Sksagiyam + 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)
2235f84dd6b4Sksagiyam - 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)
2236f84dd6b4Sksagiyam 
2237f84dd6b4Sksagiyam   Level: advanced
2238f84dd6b4Sksagiyam 
2239f84dd6b4Sksagiyam   Notes:
2240f84dd6b4Sksagiyam   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.
2241f84dd6b4Sksagiyam 
2242f84dd6b4Sksagiyam   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.
2243f84dd6b4Sksagiyam 
2244f84dd6b4Sksagiyam   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.
2245f84dd6b4Sksagiyam 
2246f84dd6b4Sksagiyam   Example using 2 processes:
2247f84dd6b4Sksagiyam $  NX (number of points on dm): 4
2248f84dd6b4Sksagiyam $  sectionA                   : the on-disk section
2249f84dd6b4Sksagiyam $  vecA                       : a vector associated with sectionA
2250f84dd6b4Sksagiyam $  sectionB                   : sectiondm's local section constructed in this function
2251f84dd6b4Sksagiyam $  vecB (local)               : a vector associated with sectiondm's local section
2252f84dd6b4Sksagiyam $  vecB (global)              : a vector associated with sectiondm's global section
2253f84dd6b4Sksagiyam $
2254f84dd6b4Sksagiyam $                                     rank 0    rank 1
2255f84dd6b4Sksagiyam $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2256f84dd6b4Sksagiyam $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2257f84dd6b4Sksagiyam $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2258f84dd6b4Sksagiyam $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2259f84dd6b4Sksagiyam $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2260f84dd6b4Sksagiyam $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2261f84dd6b4Sksagiyam $  sectionB->atlasDof             :     1 0 1 | 1 3
2262f84dd6b4Sksagiyam $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2263f84dd6b4Sksagiyam $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2264f84dd6b4Sksagiyam $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2265f84dd6b4Sksagiyam $
2266f84dd6b4Sksagiyam $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2267f84dd6b4Sksagiyam 
2268db781477SPatrick Sanan .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`
2269f84dd6b4Sksagiyam @*/
2270f84dd6b4Sksagiyam PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2271f84dd6b4Sksagiyam {
2272f84dd6b4Sksagiyam   PetscBool      ishdf5;
2273f84dd6b4Sksagiyam 
2274f84dd6b4Sksagiyam   PetscFunctionBegin;
2275f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2276f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2277f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2278f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2279f84dd6b4Sksagiyam   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2280f84dd6b4Sksagiyam   if (localDofSF) PetscValidPointer(localDofSF, 6);
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
22829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0));
2283f84dd6b4Sksagiyam   if (ishdf5) {
2284f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
22859566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2286f84dd6b4Sksagiyam #else
2287f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2288f84dd6b4Sksagiyam #endif
2289f84dd6b4Sksagiyam   }
22909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0));
2291f84dd6b4Sksagiyam   PetscFunctionReturn(0);
2292f84dd6b4Sksagiyam }
2293f84dd6b4Sksagiyam 
22948be3dfe1Sksagiyam /*@
22958be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
22968be3dfe1Sksagiyam 
22978be3dfe1Sksagiyam   Collective on DM
22988be3dfe1Sksagiyam 
22998be3dfe1Sksagiyam   Input Parameters:
23008be3dfe1Sksagiyam + dm        - The DM that represents the topology
23018be3dfe1Sksagiyam . viewer    - The PetscViewer that represents the on-disk vector data
23028be3dfe1Sksagiyam . sectiondm - The DM that contains the global section on which vec is defined
23038be3dfe1Sksagiyam . sf        - The SF that migrates the on-disk vector data into vec
23048be3dfe1Sksagiyam - vec       - The global vector to set values of
23058be3dfe1Sksagiyam 
23068be3dfe1Sksagiyam   Level: advanced
23078be3dfe1Sksagiyam 
23088be3dfe1Sksagiyam   Notes:
23098be3dfe1Sksagiyam   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.
23108be3dfe1Sksagiyam 
23118be3dfe1Sksagiyam   Typical calling sequence
23128be3dfe1Sksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
23138be3dfe1Sksagiyam $       DMSetType(dm, DMPLEX);
23148be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
23158be3dfe1Sksagiyam $       DMPlexTopologyLoad(dm, viewer, &sfX);
23168be3dfe1Sksagiyam $       DMClone(dm, &sectiondm);
23178be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
23188be3dfe1Sksagiyam $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
23198be3dfe1Sksagiyam $       DMGetGlobalVector(sectiondm, &vec);
23208be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
23218be3dfe1Sksagiyam $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
23228be3dfe1Sksagiyam $       DMRestoreGlobalVector(sectiondm, &vec);
23238be3dfe1Sksagiyam $       PetscSFDestroy(&gsf);
23248be3dfe1Sksagiyam $       PetscSFDestroy(&sfX);
23258be3dfe1Sksagiyam $       DMDestroy(&sectiondm);
23268be3dfe1Sksagiyam $       DMDestroy(&dm);
23278be3dfe1Sksagiyam 
2328db781477SPatrick Sanan .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`
23298be3dfe1Sksagiyam @*/
23308be3dfe1Sksagiyam PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
23318be3dfe1Sksagiyam {
23328be3dfe1Sksagiyam   PetscBool       ishdf5;
23338be3dfe1Sksagiyam 
23348be3dfe1Sksagiyam   PetscFunctionBegin;
23358be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23368be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23378be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
23388be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
23398be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
23408be3dfe1Sksagiyam   /* Check consistency */
23418be3dfe1Sksagiyam   {
23428be3dfe1Sksagiyam     PetscSection  section;
23438be3dfe1Sksagiyam     PetscBool     includesConstraints;
23448be3dfe1Sksagiyam     PetscInt      m, m1;
23458be3dfe1Sksagiyam 
23469566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
23479566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
23489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
23499566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
23509566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
235163a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
23528be3dfe1Sksagiyam   }
23539566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
23549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0));
23558be3dfe1Sksagiyam   if (ishdf5) {
23568be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
23579566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
23588be3dfe1Sksagiyam #else
23598be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23608be3dfe1Sksagiyam #endif
23618be3dfe1Sksagiyam   }
23629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0));
23638be3dfe1Sksagiyam   PetscFunctionReturn(0);
23648be3dfe1Sksagiyam }
23658be3dfe1Sksagiyam 
23668be3dfe1Sksagiyam /*@
23678be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
23688be3dfe1Sksagiyam 
23698be3dfe1Sksagiyam   Collective on DM
23708be3dfe1Sksagiyam 
23718be3dfe1Sksagiyam   Input Parameters:
23728be3dfe1Sksagiyam + dm        - The DM that represents the topology
23738be3dfe1Sksagiyam . viewer    - The PetscViewer that represents the on-disk vector data
23748be3dfe1Sksagiyam . sectiondm - The DM that contains the local section on which vec is defined
23758be3dfe1Sksagiyam . sf        - The SF that migrates the on-disk vector data into vec
23768be3dfe1Sksagiyam - vec       - The local vector to set values of
23778be3dfe1Sksagiyam 
23788be3dfe1Sksagiyam   Level: advanced
23798be3dfe1Sksagiyam 
23808be3dfe1Sksagiyam   Notes:
23818be3dfe1Sksagiyam   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.
23828be3dfe1Sksagiyam 
23838be3dfe1Sksagiyam   Typical calling sequence
23848be3dfe1Sksagiyam $       DMCreate(PETSC_COMM_WORLD, &dm);
23858be3dfe1Sksagiyam $       DMSetType(dm, DMPLEX);
23868be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
23878be3dfe1Sksagiyam $       DMPlexTopologyLoad(dm, viewer, &sfX);
23888be3dfe1Sksagiyam $       DMClone(dm, &sectiondm);
23898be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
23908be3dfe1Sksagiyam $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
23918be3dfe1Sksagiyam $       DMGetLocalVector(sectiondm, &vec);
23928be3dfe1Sksagiyam $       PetscObjectSetName((PetscObject)vec, "vec_name");
23938be3dfe1Sksagiyam $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
23948be3dfe1Sksagiyam $       DMRestoreLocalVector(sectiondm, &vec);
23958be3dfe1Sksagiyam $       PetscSFDestroy(&lsf);
23968be3dfe1Sksagiyam $       PetscSFDestroy(&sfX);
23978be3dfe1Sksagiyam $       DMDestroy(&sectiondm);
23988be3dfe1Sksagiyam $       DMDestroy(&dm);
23998be3dfe1Sksagiyam 
2400db781477SPatrick Sanan .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`
24018be3dfe1Sksagiyam @*/
24028be3dfe1Sksagiyam PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
24038be3dfe1Sksagiyam {
24048be3dfe1Sksagiyam   PetscBool       ishdf5;
24058be3dfe1Sksagiyam 
24068be3dfe1Sksagiyam   PetscFunctionBegin;
24078be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24088be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24098be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24108be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
24118be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
24128be3dfe1Sksagiyam   /* Check consistency */
24138be3dfe1Sksagiyam   {
24148be3dfe1Sksagiyam     PetscSection  section;
24158be3dfe1Sksagiyam     PetscBool     includesConstraints;
24168be3dfe1Sksagiyam     PetscInt      m, m1;
24178be3dfe1Sksagiyam 
24189566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24199566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
24209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24219566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24229566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
242363a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
24248be3dfe1Sksagiyam   }
24259566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
24269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0));
24278be3dfe1Sksagiyam   if (ishdf5) {
24288be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
24299566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
24308be3dfe1Sksagiyam #else
24318be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24328be3dfe1Sksagiyam #endif
24338be3dfe1Sksagiyam   }
24349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0));
24358be3dfe1Sksagiyam   PetscFunctionReturn(0);
24368be3dfe1Sksagiyam }
24378be3dfe1Sksagiyam 
2438552f7358SJed Brown PetscErrorCode DMDestroy_Plex(DM dm)
2439552f7358SJed Brown {
2440552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2441552f7358SJed Brown 
2442552f7358SJed Brown   PetscFunctionBegin;
24439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL));
24449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL));
24459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL));
24469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL));
24470d644c17SKarl Rupp   if (--mesh->refct > 0) PetscFunctionReturn(0);
24489566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
24499566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
24509566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
24519566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
24529566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
24539566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
24549566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->facesTmp));
24559566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
24569566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
24579566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
24589566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
24599566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
24609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
24619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
24629566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
24639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
24649566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
24659566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
24669566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
24679566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
24689566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
24699566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
24709566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
24719566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
24729566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
24739566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2474552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
24759566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
2476552f7358SJed Brown   PetscFunctionReturn(0);
2477552f7358SJed Brown }
2478552f7358SJed Brown 
2479b412c318SBarry Smith PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2480552f7358SJed Brown {
24818d1174e4SMatthew G. Knepley   PetscSection           sectionGlobal;
2482acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
2483*9fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2484837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2485b412c318SBarry Smith   MatType                mtype;
24861428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2487552f7358SJed Brown 
2488552f7358SJed Brown   PetscFunctionBegin;
24899566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2490b412c318SBarry Smith   mtype = dm->mattype;
24919566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
24929566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
24939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2494*9fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm)));
24959566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
24969566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
24979566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
24989566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
24999566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2500acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
25019566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
25029566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
25039566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
25049566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
25059566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
25069566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
25079566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
25089566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2509552f7358SJed Brown   if (!isShell) {
2510837628f4SStefano Zampini     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2511*9fca9976SJed Brown     PetscInt  *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2512fad22124SMatthew G Knepley     PetscInt  pStart, pEnd, p, dof, cdof;
2513552f7358SJed Brown 
25149566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm,&ltog));
2515*9fca9976SJed Brown 
2516*9fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
25179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2518e432b41dSStefano Zampini     for (p = pStart; p < pEnd; ++p) {
2519*9fca9976SJed Brown       PetscInt bdof, offset;
2520a9d99c84SMatthew G. Knepley 
25219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
2522*9fca9976SJed Brown       PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
25239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2524*9fca9976SJed Brown       for (PetscInt i=0; i < dof - cdof; i++)
2525*9fca9976SJed Brown         pblocks[offset - localStart + i] = dof - cdof;
25261d17a0a3SMatthew G. Knepley       dof  = dof < 0 ? -(dof+1) : dof;
25271d17a0a3SMatthew G. Knepley       bdof = cdof && (dof-cdof) ? 1 : dof;
25281d17a0a3SMatthew G. Knepley       if (dof) {
25291d17a0a3SMatthew G. Knepley         if (bs < 0)          {bs = bdof;}
2530*9fca9976SJed Brown         else if (bs != bdof) {bs = 1;}
2531552f7358SJed Brown       }
25322a28c762SMatthew G Knepley     }
25332a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2534e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2535e432b41dSStefano Zampini     bsLocal[1] = bs;
25369566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax));
2537e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2538e432b41dSStefano Zampini     else bs = bsMinMax[0];
25396fd5c86aSStefano Zampini     bs = PetscMax(1,bs);
25409566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog));
25410682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
25429566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
25439566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
25440682b8bbSJed Brown     } else {
25459566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu));
25469566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
25479566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2548552f7358SJed Brown     }
2549*9fca9976SJed Brown     { // Consolidate blocks
2550*9fca9976SJed Brown       PetscInt nblocks = 0;
2551*9fca9976SJed Brown       for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) {
2552*9fca9976SJed Brown         if (pblocks[i] == 0) continue;
2553*9fca9976SJed Brown         pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2554*9fca9976SJed Brown         for (PetscInt j=1; j<pblocks[i]; j++) {
2555*9fca9976SJed 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]);
2556*9fca9976SJed Brown         }
2557*9fca9976SJed Brown       }
2558*9fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
2559*9fca9976SJed Brown     }
2560*9fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2561aa0f6e3cSJed Brown   }
25629566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
2563552f7358SJed Brown   PetscFunctionReturn(0);
2564552f7358SJed Brown }
2565552f7358SJed Brown 
25667cd05799SMatthew G. Knepley /*@
2567a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2568be36d101SStefano Zampini 
2569be36d101SStefano Zampini   Not collective
2570be36d101SStefano Zampini 
2571be36d101SStefano Zampini   Input Parameter:
2572be36d101SStefano Zampini . mesh - The DMPlex
2573be36d101SStefano Zampini 
2574be36d101SStefano Zampini   Output Parameters:
2575be36d101SStefano Zampini . subsection - The subdomain section
2576be36d101SStefano Zampini 
2577be36d101SStefano Zampini   Level: developer
2578be36d101SStefano Zampini 
2579be36d101SStefano Zampini .seealso:
25807cd05799SMatthew G. Knepley @*/
2581be36d101SStefano Zampini PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2582be36d101SStefano Zampini {
2583be36d101SStefano Zampini   DM_Plex       *mesh = (DM_Plex*) dm->data;
2584be36d101SStefano Zampini 
2585be36d101SStefano Zampini   PetscFunctionBegin;
2586be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2587be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2588be36d101SStefano Zampini     PetscSection section;
2589be36d101SStefano Zampini     PetscSF      sf;
2590be36d101SStefano Zampini 
25919566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf));
25929566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm,&section));
25939566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection));
25949566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2595be36d101SStefano Zampini   }
2596be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
2597be36d101SStefano Zampini   PetscFunctionReturn(0);
2598be36d101SStefano Zampini }
2599be36d101SStefano Zampini 
2600552f7358SJed Brown /*@
2601552f7358SJed Brown   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2602552f7358SJed Brown 
2603552f7358SJed Brown   Not collective
2604552f7358SJed Brown 
2605552f7358SJed Brown   Input Parameter:
2606552f7358SJed Brown . mesh - The DMPlex
2607552f7358SJed Brown 
2608552f7358SJed Brown   Output Parameters:
2609552f7358SJed Brown + pStart - The first mesh point
2610552f7358SJed Brown - pEnd   - The upper bound for mesh points
2611552f7358SJed Brown 
2612552f7358SJed Brown   Level: beginner
2613552f7358SJed Brown 
2614db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetChart()`
2615552f7358SJed Brown @*/
2616552f7358SJed Brown PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2617552f7358SJed Brown {
2618552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2619552f7358SJed Brown 
2620552f7358SJed Brown   PetscFunctionBegin;
2621552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2623552f7358SJed Brown   PetscFunctionReturn(0);
2624552f7358SJed Brown }
2625552f7358SJed Brown 
2626552f7358SJed Brown /*@
2627552f7358SJed Brown   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2628552f7358SJed Brown 
2629552f7358SJed Brown   Not collective
2630552f7358SJed Brown 
2631552f7358SJed Brown   Input Parameters:
2632552f7358SJed Brown + mesh - The DMPlex
2633552f7358SJed Brown . pStart - The first mesh point
2634552f7358SJed Brown - pEnd   - The upper bound for mesh points
2635552f7358SJed Brown 
2636552f7358SJed Brown   Output Parameters:
2637552f7358SJed Brown 
2638552f7358SJed Brown   Level: beginner
2639552f7358SJed Brown 
2640db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetChart()`
2641552f7358SJed Brown @*/
2642552f7358SJed Brown PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2643552f7358SJed Brown {
2644552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2645552f7358SJed Brown 
2646552f7358SJed Brown   PetscFunctionBegin;
2647552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26489566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
26499566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2650552f7358SJed Brown   PetscFunctionReturn(0);
2651552f7358SJed Brown }
2652552f7358SJed Brown 
2653552f7358SJed Brown /*@
2654eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2655552f7358SJed Brown 
2656552f7358SJed Brown   Not collective
2657552f7358SJed Brown 
2658552f7358SJed Brown   Input Parameters:
2659552f7358SJed Brown + mesh - The DMPlex
2660eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
2661552f7358SJed Brown 
2662552f7358SJed Brown   Output Parameter:
2663552f7358SJed Brown . size - The cone size for point p
2664552f7358SJed Brown 
2665552f7358SJed Brown   Level: beginner
2666552f7358SJed Brown 
2667db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2668552f7358SJed Brown @*/
2669552f7358SJed Brown PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2670552f7358SJed Brown {
2671552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2672552f7358SJed Brown 
2673552f7358SJed Brown   PetscFunctionBegin;
2674552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2675dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
26769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
2677552f7358SJed Brown   PetscFunctionReturn(0);
2678552f7358SJed Brown }
2679552f7358SJed Brown 
2680552f7358SJed Brown /*@
2681eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2682552f7358SJed Brown 
2683552f7358SJed Brown   Not collective
2684552f7358SJed Brown 
2685552f7358SJed Brown   Input Parameters:
2686552f7358SJed Brown + mesh - The DMPlex
2687eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2688552f7358SJed Brown - size - The cone size for point p
2689552f7358SJed Brown 
2690552f7358SJed Brown   Output Parameter:
2691552f7358SJed Brown 
2692552f7358SJed Brown   Note:
2693552f7358SJed Brown   This should be called after DMPlexSetChart().
2694552f7358SJed Brown 
2695552f7358SJed Brown   Level: beginner
2696552f7358SJed Brown 
2697db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2698552f7358SJed Brown @*/
2699552f7358SJed Brown PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2700552f7358SJed Brown {
2701552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2702552f7358SJed Brown 
2703552f7358SJed Brown   PetscFunctionBegin;
2704552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27059566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
2706552f7358SJed Brown   PetscFunctionReturn(0);
2707552f7358SJed Brown }
2708552f7358SJed Brown 
2709f5a469b9SMatthew G. Knepley /*@
2710eaf898f9SPatrick Sanan   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2711f5a469b9SMatthew G. Knepley 
2712f5a469b9SMatthew G. Knepley   Not collective
2713f5a469b9SMatthew G. Knepley 
2714f5a469b9SMatthew G. Knepley   Input Parameters:
2715f5a469b9SMatthew G. Knepley + mesh - The DMPlex
2716eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2717f5a469b9SMatthew G. Knepley - size - The additional cone size for point p
2718f5a469b9SMatthew G. Knepley 
2719f5a469b9SMatthew G. Knepley   Output Parameter:
2720f5a469b9SMatthew G. Knepley 
2721f5a469b9SMatthew G. Knepley   Note:
2722f5a469b9SMatthew G. Knepley   This should be called after DMPlexSetChart().
2723f5a469b9SMatthew G. Knepley 
2724f5a469b9SMatthew G. Knepley   Level: beginner
2725f5a469b9SMatthew G. Knepley 
2726db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2727f5a469b9SMatthew G. Knepley @*/
2728f5a469b9SMatthew G. Knepley PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2729f5a469b9SMatthew G. Knepley {
2730f5a469b9SMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
2731f5a469b9SMatthew G. Knepley   PetscFunctionBegin;
2732f5a469b9SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27339566063dSJacob Faibussowitsch   PetscCall(PetscSectionAddDof(mesh->coneSection, p, size));
2734f5a469b9SMatthew G. Knepley   PetscFunctionReturn(0);
2735f5a469b9SMatthew G. Knepley }
2736f5a469b9SMatthew G. Knepley 
2737552f7358SJed Brown /*@C
2738eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2739552f7358SJed Brown 
2740552f7358SJed Brown   Not collective
2741552f7358SJed Brown 
2742552f7358SJed Brown   Input Parameters:
2743833c876bSVaclav Hapla + dm - The DMPlex
2744eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
2745552f7358SJed Brown 
2746552f7358SJed Brown   Output Parameter:
2747552f7358SJed Brown . cone - An array of points which are on the in-edges for point p
2748552f7358SJed Brown 
2749552f7358SJed Brown   Level: beginner
2750552f7358SJed Brown 
27513813dfbdSMatthew G Knepley   Fortran Notes:
27523813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
27533813dfbdSMatthew G Knepley   include petsc.h90 in your code.
2754922102d1SVaclav Hapla   You must also call DMPlexRestoreCone() after you finish using the returned array.
2755922102d1SVaclav Hapla   DMPlexRestoreCone() is not needed/available in C.
27563813dfbdSMatthew G Knepley 
2757db781477SPatrick Sanan .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`
2758552f7358SJed Brown @*/
2759552f7358SJed Brown PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2760552f7358SJed Brown {
2761552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2762552f7358SJed Brown   PetscInt       off;
2763552f7358SJed Brown 
2764552f7358SJed Brown   PetscFunctionBegin;
2765552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2766552f7358SJed Brown   PetscValidPointer(cone, 3);
27679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
2768552f7358SJed Brown   *cone = &mesh->cones[off];
2769552f7358SJed Brown   PetscFunctionReturn(0);
2770552f7358SJed Brown }
2771552f7358SJed Brown 
27720ce7577fSVaclav Hapla /*@C
27730ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
27740ce7577fSVaclav Hapla 
27750ce7577fSVaclav Hapla   Not collective
27760ce7577fSVaclav Hapla 
27770ce7577fSVaclav Hapla   Input Parameters:
27780ce7577fSVaclav Hapla + dm - The DMPlex
27790ce7577fSVaclav Hapla - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
27800ce7577fSVaclav Hapla 
2781d8d19677SJose E. Roman   Output Parameters:
27820ce7577fSVaclav Hapla + pConesSection - PetscSection describing the layout of pCones
27830ce7577fSVaclav Hapla - pCones - An array of points which are on the in-edges for the point set p
27840ce7577fSVaclav Hapla 
27850ce7577fSVaclav Hapla   Level: intermediate
27860ce7577fSVaclav Hapla 
2787db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`
27880ce7577fSVaclav Hapla @*/
27890ce7577fSVaclav Hapla PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
27900ce7577fSVaclav Hapla {
27910ce7577fSVaclav Hapla   PetscSection        cs, newcs;
27920ce7577fSVaclav Hapla   PetscInt            *cones;
27930ce7577fSVaclav Hapla   PetscInt            *newarr=NULL;
27940ce7577fSVaclav Hapla   PetscInt            n;
27950ce7577fSVaclav Hapla 
27960ce7577fSVaclav Hapla   PetscFunctionBegin;
27979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
27989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
27999566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL));
28000ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
28010ce7577fSVaclav Hapla   if (pCones) {
28029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
28039566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
28040ce7577fSVaclav Hapla   }
28050ce7577fSVaclav Hapla   PetscFunctionReturn(0);
28060ce7577fSVaclav Hapla }
28070ce7577fSVaclav Hapla 
2808af9eab45SVaclav Hapla /*@
2809af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2810d4636a37SVaclav Hapla 
2811d4636a37SVaclav Hapla   Not collective
2812d4636a37SVaclav Hapla 
2813d4636a37SVaclav Hapla   Input Parameters:
2814d4636a37SVaclav Hapla + dm - The DMPlex
2815af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2816d4636a37SVaclav Hapla 
2817d4636a37SVaclav Hapla   Output Parameter:
2818af9eab45SVaclav Hapla . expandedPoints - An array of vertices recursively expanded from input points
2819d4636a37SVaclav Hapla 
2820d4636a37SVaclav Hapla   Level: advanced
2821d4636a37SVaclav Hapla 
2822af9eab45SVaclav Hapla   Notes:
2823af9eab45SVaclav Hapla   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2824af9eab45SVaclav Hapla   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2825af9eab45SVaclav Hapla 
2826db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()`
2827d4636a37SVaclav Hapla @*/
2828af9eab45SVaclav Hapla PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2829d4636a37SVaclav Hapla {
2830af9eab45SVaclav Hapla   IS                  *expandedPointsAll;
2831af9eab45SVaclav Hapla   PetscInt            depth;
2832d4636a37SVaclav Hapla 
2833d4636a37SVaclav Hapla   PetscFunctionBegin;
2834af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2835af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2836af9eab45SVaclav Hapla   PetscValidPointer(expandedPoints, 3);
28379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2838af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
28399566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
28409566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2841af9eab45SVaclav Hapla   PetscFunctionReturn(0);
2842af9eab45SVaclav Hapla }
2843af9eab45SVaclav Hapla 
2844af9eab45SVaclav Hapla /*@
2845af9eab45SVaclav 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).
2846af9eab45SVaclav Hapla 
2847af9eab45SVaclav Hapla   Not collective
2848af9eab45SVaclav Hapla 
2849af9eab45SVaclav Hapla   Input Parameters:
2850af9eab45SVaclav Hapla + dm - The DMPlex
2851af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2852af9eab45SVaclav Hapla 
2853d8d19677SJose E. Roman   Output Parameters:
2854af9eab45SVaclav Hapla + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2855af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
2856af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
2857af9eab45SVaclav Hapla 
2858af9eab45SVaclav Hapla   Level: advanced
2859af9eab45SVaclav Hapla 
2860af9eab45SVaclav Hapla   Notes:
2861af9eab45SVaclav Hapla   Like DMPlexGetConeTuple() but recursive.
2862af9eab45SVaclav Hapla 
2863af9eab45SVaclav 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.
2864af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2865af9eab45SVaclav Hapla 
2866af9eab45SVaclav 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:
2867af9eab45SVaclav Hapla   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2868af9eab45SVaclav Hapla   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2869af9eab45SVaclav Hapla 
2870db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()`
2871af9eab45SVaclav Hapla @*/
2872af9eab45SVaclav Hapla PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2873af9eab45SVaclav Hapla {
2874af9eab45SVaclav Hapla   const PetscInt      *arr0=NULL, *cone=NULL;
2875af9eab45SVaclav Hapla   PetscInt            *arr=NULL, *newarr=NULL;
2876af9eab45SVaclav Hapla   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2877af9eab45SVaclav Hapla   IS                  *expandedPoints_;
2878af9eab45SVaclav Hapla   PetscSection        *sections_;
2879af9eab45SVaclav Hapla 
2880af9eab45SVaclav Hapla   PetscFunctionBegin;
2881af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2882af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2883af9eab45SVaclav Hapla   if (depth) PetscValidIntPointer(depth, 3);
2884af9eab45SVaclav Hapla   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2885af9eab45SVaclav Hapla   if (sections) PetscValidPointer(sections, 5);
28869566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
28879566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
28889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
28899566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
28909566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
2891af9eab45SVaclav Hapla   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2892af9eab45SVaclav Hapla   for (d=depth_-1; d>=0; d--) {
28939566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
28949566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
2895af9eab45SVaclav Hapla     for (i=0; i<n; i++) {
28969566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end));
2897af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
28989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
28999566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
2900af9eab45SVaclav Hapla       } else {
29019566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
2902af9eab45SVaclav Hapla       }
2903af9eab45SVaclav Hapla     }
29049566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
29059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
29069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
2907af9eab45SVaclav Hapla     for (i=0; i<n; i++) {
29089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
29099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
2910af9eab45SVaclav Hapla       if (cn > 1) {
29119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
29129566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt)));
2913af9eab45SVaclav Hapla       } else {
2914af9eab45SVaclav Hapla         newarr[co] = arr[i];
2915af9eab45SVaclav Hapla       }
2916af9eab45SVaclav Hapla     }
29179566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
2918af9eab45SVaclav Hapla     arr = newarr;
2919af9eab45SVaclav Hapla     n = newn;
2920af9eab45SVaclav Hapla   }
29219566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
2922af9eab45SVaclav Hapla   *depth = depth_;
2923af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
2924af9eab45SVaclav Hapla   else {
29259566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
29269566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
2927af9eab45SVaclav Hapla   }
2928af9eab45SVaclav Hapla   if (sections) *sections = sections_;
2929af9eab45SVaclav Hapla   else {
29309566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
29319566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
2932af9eab45SVaclav Hapla   }
2933af9eab45SVaclav Hapla   PetscFunctionReturn(0);
2934af9eab45SVaclav Hapla }
2935af9eab45SVaclav Hapla 
2936af9eab45SVaclav Hapla /*@
2937af9eab45SVaclav Hapla   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2938af9eab45SVaclav Hapla 
2939af9eab45SVaclav Hapla   Not collective
2940af9eab45SVaclav Hapla 
2941af9eab45SVaclav Hapla   Input Parameters:
2942af9eab45SVaclav Hapla + dm - The DMPlex
2943af9eab45SVaclav Hapla - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2944af9eab45SVaclav Hapla 
2945d8d19677SJose E. Roman   Output Parameters:
2946af9eab45SVaclav Hapla + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2947af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
2948af9eab45SVaclav Hapla - sections - (optional) An array of sections which describe mappings from points to their cone points
2949af9eab45SVaclav Hapla 
2950af9eab45SVaclav Hapla   Level: advanced
2951af9eab45SVaclav Hapla 
2952af9eab45SVaclav Hapla   Notes:
2953af9eab45SVaclav Hapla   See DMPlexGetConeRecursive() for details.
2954af9eab45SVaclav Hapla 
2955db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()`
2956af9eab45SVaclav Hapla @*/
2957af9eab45SVaclav Hapla PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2958af9eab45SVaclav Hapla {
2959af9eab45SVaclav Hapla   PetscInt            d, depth_;
2960af9eab45SVaclav Hapla 
2961af9eab45SVaclav Hapla   PetscFunctionBegin;
29629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
29631dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2964af9eab45SVaclav Hapla   if (depth) *depth = 0;
2965af9eab45SVaclav Hapla   if (expandedPoints) {
29669566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
29679566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
2968af9eab45SVaclav Hapla   }
2969af9eab45SVaclav Hapla   if (sections)  {
29709566063dSJacob Faibussowitsch     for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
29719566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
2972af9eab45SVaclav Hapla   }
2973d4636a37SVaclav Hapla   PetscFunctionReturn(0);
2974d4636a37SVaclav Hapla }
2975d4636a37SVaclav Hapla 
2976552f7358SJed Brown /*@
297792371b87SBarry 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
2978552f7358SJed Brown 
2979552f7358SJed Brown   Not collective
2980552f7358SJed Brown 
2981552f7358SJed Brown   Input Parameters:
2982552f7358SJed Brown + mesh - The DMPlex
2983eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
2984552f7358SJed Brown - cone - An array of points which are on the in-edges for point p
2985552f7358SJed Brown 
2986552f7358SJed Brown   Output Parameter:
2987552f7358SJed Brown 
2988552f7358SJed Brown   Note:
2989552f7358SJed Brown   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2990552f7358SJed Brown 
2991552f7358SJed Brown   Level: beginner
2992552f7358SJed Brown 
2993db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
2994552f7358SJed Brown @*/
2995552f7358SJed Brown PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
2996552f7358SJed Brown {
2997552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
2998552f7358SJed Brown   PetscInt       pStart, pEnd;
2999552f7358SJed Brown   PetscInt       dof, off, c;
3000552f7358SJed Brown 
3001552f7358SJed Brown   PetscFunctionBegin;
3002552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
30049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3005dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(cone, 3);
30069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
300763a3b9bcSJacob 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);
3008552f7358SJed Brown   for (c = 0; c < dof; ++c) {
300963a3b9bcSJacob 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);
3010552f7358SJed Brown     mesh->cones[off+c] = cone[c];
3011552f7358SJed Brown   }
3012552f7358SJed Brown   PetscFunctionReturn(0);
3013552f7358SJed Brown }
3014552f7358SJed Brown 
3015552f7358SJed Brown /*@C
3016eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3017552f7358SJed Brown 
3018552f7358SJed Brown   Not collective
3019552f7358SJed Brown 
3020552f7358SJed Brown   Input Parameters:
3021552f7358SJed Brown + mesh - The DMPlex
3022eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3023552f7358SJed Brown 
3024552f7358SJed Brown   Output Parameter:
3025552f7358SJed Brown . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
3026b5a892a1SMatthew G. Knepley                     integer giving the prescription for cone traversal.
3027552f7358SJed Brown 
3028552f7358SJed Brown   Level: beginner
3029552f7358SJed Brown 
3030b5a892a1SMatthew G. Knepley   Notes:
3031b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3032b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3033b5a892a1SMatthew G. Knepley   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
3034b5a892a1SMatthew G. Knepley   with the identity.
3035b5a892a1SMatthew G. Knepley 
30363813dfbdSMatthew G Knepley   Fortran Notes:
30373813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
30383813dfbdSMatthew G Knepley   include petsc.h90 in your code.
30393b12b3d8SVaclav Hapla   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
3040922102d1SVaclav Hapla   DMPlexRestoreConeOrientation() is not needed/available in C.
30413813dfbdSMatthew G Knepley 
3042db781477SPatrick Sanan .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3043552f7358SJed Brown @*/
3044552f7358SJed Brown PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3045552f7358SJed Brown {
3046552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3047552f7358SJed Brown   PetscInt       off;
3048552f7358SJed Brown 
3049552f7358SJed Brown   PetscFunctionBegin;
3050552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
305176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3052552f7358SJed Brown     PetscInt dof;
30539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3054552f7358SJed Brown     if (dof) PetscValidPointer(coneOrientation, 3);
3055552f7358SJed Brown   }
30569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
30570d644c17SKarl Rupp 
3058552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
3059552f7358SJed Brown   PetscFunctionReturn(0);
3060552f7358SJed Brown }
3061552f7358SJed Brown 
3062552f7358SJed Brown /*@
3063eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3064552f7358SJed Brown 
3065552f7358SJed Brown   Not collective
3066552f7358SJed Brown 
3067552f7358SJed Brown   Input Parameters:
3068552f7358SJed Brown + mesh - The DMPlex
3069eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3070b5a892a1SMatthew G. Knepley - coneOrientation - An array of orientations
3071552f7358SJed Brown   Output Parameter:
3072552f7358SJed Brown 
3073b5a892a1SMatthew G. Knepley   Notes:
3074552f7358SJed Brown   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
3075552f7358SJed Brown 
3076b5a892a1SMatthew G. Knepley   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
3077b5a892a1SMatthew G. Knepley 
3078552f7358SJed Brown   Level: beginner
3079552f7358SJed Brown 
3080db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3081552f7358SJed Brown @*/
3082552f7358SJed Brown PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3083552f7358SJed Brown {
3084552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3085552f7358SJed Brown   PetscInt       pStart, pEnd;
3086552f7358SJed Brown   PetscInt       dof, off, c;
3087552f7358SJed Brown 
3088552f7358SJed Brown   PetscFunctionBegin;
3089552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
30919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3092dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(coneOrientation, 3);
30939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
309463a3b9bcSJacob Faibussowitsch   PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3095552f7358SJed Brown   for (c = 0; c < dof; ++c) {
3096552f7358SJed Brown     PetscInt cdof, o = coneOrientation[c];
3097552f7358SJed Brown 
30989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof));
30991dca8a05SBarry 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);
3100552f7358SJed Brown     mesh->coneOrientations[off+c] = o;
3101552f7358SJed Brown   }
3102552f7358SJed Brown   PetscFunctionReturn(0);
3103552f7358SJed Brown }
3104552f7358SJed Brown 
31057cd05799SMatthew G. Knepley /*@
3106eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
31077cd05799SMatthew G. Knepley 
31087cd05799SMatthew G. Knepley   Not collective
31097cd05799SMatthew G. Knepley 
31107cd05799SMatthew G. Knepley   Input Parameters:
31117cd05799SMatthew G. Knepley + mesh - The DMPlex
3112eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
31137cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
31147cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
31157cd05799SMatthew G. Knepley 
31167cd05799SMatthew G. Knepley   Level: beginner
31177cd05799SMatthew G. Knepley 
3118db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
31197cd05799SMatthew G. Knepley @*/
3120552f7358SJed Brown PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3121552f7358SJed Brown {
3122552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3123552f7358SJed Brown   PetscInt       pStart, pEnd;
3124552f7358SJed Brown   PetscInt       dof, off;
3125552f7358SJed Brown 
3126552f7358SJed Brown   PetscFunctionBegin;
3127552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
312963a3b9bcSJacob 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);
313063a3b9bcSJacob 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);
31319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
31329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
313363a3b9bcSJacob 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);
3134552f7358SJed Brown   mesh->cones[off+conePos] = conePoint;
3135552f7358SJed Brown   PetscFunctionReturn(0);
3136552f7358SJed Brown }
3137552f7358SJed Brown 
31387cd05799SMatthew G. Knepley /*@
3139eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
31407cd05799SMatthew G. Knepley 
31417cd05799SMatthew G. Knepley   Not collective
31427cd05799SMatthew G. Knepley 
31437cd05799SMatthew G. Knepley   Input Parameters:
31447cd05799SMatthew G. Knepley + mesh - The DMPlex
3145eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
31467cd05799SMatthew G. Knepley . conePos - The local index in the cone where the point should be put
31477cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
31487cd05799SMatthew G. Knepley 
31497cd05799SMatthew G. Knepley   Level: beginner
31507cd05799SMatthew G. Knepley 
3151b5a892a1SMatthew G. Knepley   Notes:
3152b5a892a1SMatthew G. Knepley   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3153b5a892a1SMatthew G. Knepley 
3154db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
31557cd05799SMatthew G. Knepley @*/
315677c88f5bSMatthew G Knepley PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
315777c88f5bSMatthew G Knepley {
315877c88f5bSMatthew G Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
315977c88f5bSMatthew G Knepley   PetscInt       pStart, pEnd;
316077c88f5bSMatthew G Knepley   PetscInt       dof, off;
316177c88f5bSMatthew G Knepley 
316277c88f5bSMatthew G Knepley   PetscFunctionBegin;
316377c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
316563a3b9bcSJacob 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);
31669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
31679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
316863a3b9bcSJacob 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);
316977c88f5bSMatthew G Knepley   mesh->coneOrientations[off+conePos] = coneOrientation;
317077c88f5bSMatthew G Knepley   PetscFunctionReturn(0);
317177c88f5bSMatthew G Knepley }
317277c88f5bSMatthew G Knepley 
3173552f7358SJed Brown /*@
3174eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3175552f7358SJed Brown 
3176552f7358SJed Brown   Not collective
3177552f7358SJed Brown 
3178552f7358SJed Brown   Input Parameters:
3179552f7358SJed Brown + mesh - The DMPlex
3180eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3181552f7358SJed Brown 
3182552f7358SJed Brown   Output Parameter:
3183552f7358SJed Brown . size - The support size for point p
3184552f7358SJed Brown 
3185552f7358SJed Brown   Level: beginner
3186552f7358SJed Brown 
3187db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3188552f7358SJed Brown @*/
3189552f7358SJed Brown PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3190552f7358SJed Brown {
3191552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3192552f7358SJed Brown 
3193552f7358SJed Brown   PetscFunctionBegin;
3194552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3195dadcf809SJacob Faibussowitsch   PetscValidIntPointer(size, 3);
31969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3197552f7358SJed Brown   PetscFunctionReturn(0);
3198552f7358SJed Brown }
3199552f7358SJed Brown 
3200552f7358SJed Brown /*@
3201eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3202552f7358SJed Brown 
3203552f7358SJed Brown   Not collective
3204552f7358SJed Brown 
3205552f7358SJed Brown   Input Parameters:
3206552f7358SJed Brown + mesh - The DMPlex
3207eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
3208552f7358SJed Brown - size - The support size for point p
3209552f7358SJed Brown 
3210552f7358SJed Brown   Output Parameter:
3211552f7358SJed Brown 
3212552f7358SJed Brown   Note:
3213552f7358SJed Brown   This should be called after DMPlexSetChart().
3214552f7358SJed Brown 
3215552f7358SJed Brown   Level: beginner
3216552f7358SJed Brown 
3217db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3218552f7358SJed Brown @*/
3219552f7358SJed Brown PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3220552f7358SJed Brown {
3221552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3222552f7358SJed Brown 
3223552f7358SJed Brown   PetscFunctionBegin;
3224552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32259566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3226552f7358SJed Brown   PetscFunctionReturn(0);
3227552f7358SJed Brown }
3228552f7358SJed Brown 
3229552f7358SJed Brown /*@C
3230eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3231552f7358SJed Brown 
3232552f7358SJed Brown   Not collective
3233552f7358SJed Brown 
3234552f7358SJed Brown   Input Parameters:
3235552f7358SJed Brown + mesh - The DMPlex
3236eaf898f9SPatrick Sanan - p - The point, which must lie in the chart set with DMPlexSetChart()
3237552f7358SJed Brown 
3238552f7358SJed Brown   Output Parameter:
3239552f7358SJed Brown . support - An array of points which are on the out-edges for point p
3240552f7358SJed Brown 
3241552f7358SJed Brown   Level: beginner
3242552f7358SJed Brown 
32433813dfbdSMatthew G Knepley   Fortran Notes:
32443813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
32453813dfbdSMatthew G Knepley   include petsc.h90 in your code.
32463b12b3d8SVaclav Hapla   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3247922102d1SVaclav Hapla   DMPlexRestoreSupport() is not needed/available in C.
32483813dfbdSMatthew G Knepley 
3249db781477SPatrick Sanan .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3250552f7358SJed Brown @*/
3251552f7358SJed Brown PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3252552f7358SJed Brown {
3253552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3254552f7358SJed Brown   PetscInt       off;
3255552f7358SJed Brown 
3256552f7358SJed Brown   PetscFunctionBegin;
3257552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3258552f7358SJed Brown   PetscValidPointer(support, 3);
32599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3260552f7358SJed Brown   *support = &mesh->supports[off];
3261552f7358SJed Brown   PetscFunctionReturn(0);
3262552f7358SJed Brown }
3263552f7358SJed Brown 
3264552f7358SJed Brown /*@
326592371b87SBarry 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
3266552f7358SJed Brown 
3267552f7358SJed Brown   Not collective
3268552f7358SJed Brown 
3269552f7358SJed Brown   Input Parameters:
3270552f7358SJed Brown + mesh - The DMPlex
3271eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
327292371b87SBarry Smith - support - An array of points which are on the out-edges for point p
3273552f7358SJed Brown 
3274552f7358SJed Brown   Output Parameter:
3275552f7358SJed Brown 
3276552f7358SJed Brown   Note:
3277552f7358SJed Brown   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3278552f7358SJed Brown 
3279552f7358SJed Brown   Level: beginner
3280552f7358SJed Brown 
3281db781477SPatrick Sanan .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3282552f7358SJed Brown @*/
3283552f7358SJed Brown PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3284552f7358SJed Brown {
3285552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3286552f7358SJed Brown   PetscInt       pStart, pEnd;
3287552f7358SJed Brown   PetscInt       dof, off, c;
3288552f7358SJed Brown 
3289552f7358SJed Brown   PetscFunctionBegin;
3290552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
32929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3293dadcf809SJacob Faibussowitsch   if (dof) PetscValidIntPointer(support, 3);
32949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
329563a3b9bcSJacob 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);
3296552f7358SJed Brown   for (c = 0; c < dof; ++c) {
329763a3b9bcSJacob 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);
3298552f7358SJed Brown     mesh->supports[off+c] = support[c];
3299552f7358SJed Brown   }
3300552f7358SJed Brown   PetscFunctionReturn(0);
3301552f7358SJed Brown }
3302552f7358SJed Brown 
33037cd05799SMatthew G. Knepley /*@
3304eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
33057cd05799SMatthew G. Knepley 
33067cd05799SMatthew G. Knepley   Not collective
33077cd05799SMatthew G. Knepley 
33087cd05799SMatthew G. Knepley   Input Parameters:
33097cd05799SMatthew G. Knepley + mesh - The DMPlex
3310eaf898f9SPatrick Sanan . p - The point, which must lie in the chart set with DMPlexSetChart()
33117cd05799SMatthew G. Knepley . supportPos - The local index in the cone where the point should be put
33127cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
33137cd05799SMatthew G. Knepley 
33147cd05799SMatthew G. Knepley   Level: beginner
33157cd05799SMatthew G. Knepley 
3316db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
33177cd05799SMatthew G. Knepley @*/
3318552f7358SJed Brown PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3319552f7358SJed Brown {
3320552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3321552f7358SJed Brown   PetscInt       pStart, pEnd;
3322552f7358SJed Brown   PetscInt       dof, off;
3323552f7358SJed Brown 
3324552f7358SJed Brown   PetscFunctionBegin;
3325552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
33279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
33289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
332963a3b9bcSJacob 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);
333063a3b9bcSJacob 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);
333163a3b9bcSJacob 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);
3332552f7358SJed Brown   mesh->supports[off+supportPos] = supportPoint;
3333552f7358SJed Brown   PetscFunctionReturn(0);
3334552f7358SJed Brown }
3335552f7358SJed Brown 
3336b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3337b5a892a1SMatthew G. Knepley PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3338b5a892a1SMatthew G. Knepley {
3339b5a892a1SMatthew G. Knepley   switch (ct) {
3340b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
3341b5a892a1SMatthew G. Knepley       if (o == -1) return -2;
3342b5a892a1SMatthew G. Knepley       break;
3343b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
3344b5a892a1SMatthew G. Knepley       if (o == -3) return -1;
3345b5a892a1SMatthew G. Knepley       if (o == -2) return -3;
3346b5a892a1SMatthew G. Knepley       if (o == -1) return -2;
3347b5a892a1SMatthew G. Knepley       break;
3348b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
3349b5a892a1SMatthew G. Knepley       if (o == -4) return -2;
3350b5a892a1SMatthew G. Knepley       if (o == -3) return -1;
3351b5a892a1SMatthew G. Knepley       if (o == -2) return -4;
3352b5a892a1SMatthew G. Knepley       if (o == -1) return -3;
3353b5a892a1SMatthew G. Knepley       break;
3354b5a892a1SMatthew G. Knepley     default: return o;
3355b5a892a1SMatthew G. Knepley   }
3356b5a892a1SMatthew G. Knepley   return o;
3357b5a892a1SMatthew G. Knepley }
3358b5a892a1SMatthew G. Knepley 
3359b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3360b5a892a1SMatthew G. Knepley PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3361b5a892a1SMatthew G. Knepley {
3362b5a892a1SMatthew G. Knepley   switch (ct) {
3363b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
3364b5a892a1SMatthew G. Knepley       if ((o == -2) || (o == 1)) return -1;
3365b5a892a1SMatthew G. Knepley       if (o == -1) return 0;
3366b5a892a1SMatthew G. Knepley       break;
3367b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
3368b5a892a1SMatthew G. Knepley       if (o == -3) return -2;
3369b5a892a1SMatthew G. Knepley       if (o == -2) return -1;
3370b5a892a1SMatthew G. Knepley       if (o == -1) return -3;
3371b5a892a1SMatthew G. Knepley       break;
3372b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
3373b5a892a1SMatthew G. Knepley       if (o == -4) return -2;
3374b5a892a1SMatthew G. Knepley       if (o == -3) return -1;
3375b5a892a1SMatthew G. Knepley       if (o == -2) return -4;
3376b5a892a1SMatthew G. Knepley       if (o == -1) return -3;
3377b5a892a1SMatthew G. Knepley       break;
3378b5a892a1SMatthew G. Knepley     default: return o;
3379b5a892a1SMatthew G. Knepley   }
3380b5a892a1SMatthew G. Knepley   return o;
3381b5a892a1SMatthew G. Knepley }
3382b5a892a1SMatthew G. Knepley 
3383b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3384b5a892a1SMatthew G. Knepley PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3385b5a892a1SMatthew G. Knepley {
3386b5a892a1SMatthew G. Knepley   PetscInt       pStart, pEnd, p;
3387b5a892a1SMatthew G. Knepley 
3388b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
33899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3390b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3391b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3392b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3393b5a892a1SMatthew G. Knepley 
33949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
33959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
33969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3397b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3398b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3399b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3400b5a892a1SMatthew G. Knepley 
34019566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3402b5a892a1SMatthew G. Knepley       switch (ct) {
3403b5a892a1SMatthew G. Knepley         case DM_POLYTOPE_SEGMENT:
34049566063dSJacob Faibussowitsch           if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
34059566063dSJacob Faibussowitsch           if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3406b5a892a1SMatthew G. Knepley           break;
3407b5a892a1SMatthew G. Knepley         case DM_POLYTOPE_TRIANGLE:
34089566063dSJacob Faibussowitsch           if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
34099566063dSJacob Faibussowitsch           if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
34109566063dSJacob Faibussowitsch           if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3411b5a892a1SMatthew G. Knepley           break;
3412b5a892a1SMatthew G. Knepley         case DM_POLYTOPE_QUADRILATERAL:
34139566063dSJacob Faibussowitsch           if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
34149566063dSJacob Faibussowitsch           if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
34159566063dSJacob Faibussowitsch           if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
34169566063dSJacob Faibussowitsch           if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3417b5a892a1SMatthew G. Knepley           break;
3418b5a892a1SMatthew G. Knepley         default: break;
3419b5a892a1SMatthew G. Knepley       }
3420b5a892a1SMatthew G. Knepley     }
3421b5a892a1SMatthew G. Knepley   }
3422b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3423b5a892a1SMatthew G. Knepley }
3424b5a892a1SMatthew G. Knepley 
3425012bc364SMatthew G. Knepley static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3426b5a892a1SMatthew G. Knepley {
3427b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3428b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3429b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3430b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3431b5a892a1SMatthew G. Knepley 
3432b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3433b5a892a1SMatthew G. Knepley   if (ornt) {
34349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3435b5a892a1SMatthew G. Knepley     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3436b5a892a1SMatthew G. Knepley   }
3437b5a892a1SMatthew G. Knepley   if (*points) {
3438b5a892a1SMatthew G. Knepley     closure = *points;
3439b5a892a1SMatthew G. Knepley   } else {
3440b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
34419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
34429566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure));
3443b5a892a1SMatthew G. Knepley   }
3444b5a892a1SMatthew G. Knepley   if (useCone) {
34459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &tmpSize));
34469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &tmp));
34479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO));
3448b5a892a1SMatthew G. Knepley   } else {
34499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize));
34509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &tmp));
3451b5a892a1SMatthew G. Knepley   }
3452b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3453b5a892a1SMatthew G. Knepley     closure[off++] = p;
3454b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3455b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3456b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3457b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3458b5a892a1SMatthew G. Knepley     }
3459b5a892a1SMatthew G. Knepley   } else {
34605f80ce2aSJacob Faibussowitsch     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3461b5a892a1SMatthew G. Knepley 
3462b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3463b5a892a1SMatthew G. Knepley     closure[off++] = p;
3464b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3465b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3466b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3467b5a892a1SMatthew G. Knepley 
34689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3469b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3470b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3471b5a892a1SMatthew G. Knepley     }
3472b5a892a1SMatthew G. Knepley   }
3473b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize+1;
3474b5a892a1SMatthew G. Knepley   if (points)    *points    = closure;
3475b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3476b5a892a1SMatthew G. Knepley }
3477b5a892a1SMatthew G. Knepley 
3478b5a892a1SMatthew G. Knepley /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3479b5a892a1SMatthew G. Knepley static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3480b5a892a1SMatthew G. Knepley {
3481b5a892a1SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3482b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3483b5a892a1SMatthew G. Knepley   PetscInt       *pts,  *closure = NULL;
3484b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3485b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3486b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3487b5a892a1SMatthew G. Knepley 
3488b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
34899566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
34909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
34919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
34929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &ornt));
34939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3494b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    dim+1)-1)/(maxConeSize-1))    : dim+1;
3495b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1;
3496b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
3497b5a892a1SMatthew G. Knepley   if (*points) {pts  = *points;}
34989566063dSJacob Faibussowitsch   else         PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts));
3499b5a892a1SMatthew G. Knepley   c    = 0;
3500b5a892a1SMatthew G. Knepley   pts[c++] = point;
3501b5a892a1SMatthew G. Knepley   pts[c++] = o;
35029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft));
35039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure));
3504b5a892a1SMatthew G. Knepley   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
35059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure));
3506b5a892a1SMatthew G. Knepley   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
35079566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3508b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
35099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft));
3510b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d*2+0]];
3511b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]);
3512b5a892a1SMatthew G. Knepley   }
3513b5a892a1SMatthew G. Knepley   if (dim >= 3) {
3514b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
3515b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d*2+0]];
3516b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
3517b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
3518b5a892a1SMatthew G. Knepley 
35199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3520b5a892a1SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]));
35219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize));
35229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, fpoint, &fcone));
35239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt));
3524b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
3525b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc*2+0]];
3526b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc*2+1];
3527b5a892a1SMatthew G. Knepley 
3528b5a892a1SMatthew G. Knepley         for (i = 0; i < c; i += 2) if (pts[i] == cp) break;
3529b5a892a1SMatthew G. Knepley         if (i == c) {
35309566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3531b5a892a1SMatthew G. Knepley           pts[c++] = cp;
3532b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]);
3533b5a892a1SMatthew G. Knepley         }
3534b5a892a1SMatthew G. Knepley       }
3535b5a892a1SMatthew G. Knepley     }
3536b5a892a1SMatthew G. Knepley   }
3537b5a892a1SMatthew G. Knepley   *numPoints = c/2;
3538b5a892a1SMatthew G. Knepley   *points    = pts;
3539b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3540b5a892a1SMatthew G. Knepley }
3541b5a892a1SMatthew G. Knepley 
3542b5a892a1SMatthew G. Knepley PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3543b5a892a1SMatthew G. Knepley {
3544b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
3545b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
3546b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3547b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3548b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
3549b5a892a1SMatthew G. Knepley 
3550b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
35519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
3552b5a892a1SMatthew G. Knepley   if (depth == 1) {
35539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3554b5a892a1SMatthew G. Knepley     PetscFunctionReturn(0);
3555b5a892a1SMatthew G. Knepley   }
35569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
3557b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3558b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
35599566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3560b5a892a1SMatthew G. Knepley     PetscFunctionReturn(0);
3561b5a892a1SMatthew G. Knepley   }
35629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3563b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    depth+1)-1)/(maxConeSize-1))    : depth+1;
3564b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1;
3565b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
35669566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo));
3567b5a892a1SMatthew G. Knepley   if (*points) {closure = *points;}
35689566063dSJacob Faibussowitsch   else         PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure));
3569b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
3570b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
3571b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
3572b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
3573b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
3574b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3575b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
3576b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
3577b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
3578b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType) fifo[fifoStart++];
3579b5a892a1SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3580b5a892a1SMatthew G. Knepley     const PetscInt      *tmp, *tmpO;
3581b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
3582b5a892a1SMatthew G. Knepley 
3583b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
3584b5a892a1SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2;
358563a3b9bcSJacob 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);
3586b5a892a1SMatthew G. Knepley     }
3587b5a892a1SMatthew G. Knepley     if (useCone) {
35889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &tmpSize));
35899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &tmp));
35909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO));
3591b5a892a1SMatthew G. Knepley     } else {
35929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize));
35939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, q, &tmp));
3594b5a892a1SMatthew G. Knepley       tmpO = NULL;
3595b5a892a1SMatthew G. Knepley     }
3596b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3597b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t*2]   : t;
3598b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0;
3599b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
36009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
3601b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3602b5a892a1SMatthew G. Knepley       PetscInt       c;
3603b5a892a1SMatthew G. Knepley 
3604b5a892a1SMatthew G. Knepley       /* Check for duplicate */
3605b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
3606b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
3607b5a892a1SMatthew G. Knepley       }
3608b5a892a1SMatthew G. Knepley       if (c == closureSize) {
3609b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
3610b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
3611b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
3612b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
3613b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
3614b5a892a1SMatthew G. Knepley       }
3615b5a892a1SMatthew G. Knepley     }
3616b5a892a1SMatthew G. Knepley   }
36179566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo));
3618b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize/2;
3619b5a892a1SMatthew G. Knepley   if (points)    *points    = closure;
3620b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
3621b5a892a1SMatthew G. Knepley }
3622b5a892a1SMatthew G. Knepley 
3623552f7358SJed Brown /*@C
3624eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3625552f7358SJed Brown 
3626552f7358SJed Brown   Not collective
3627552f7358SJed Brown 
3628552f7358SJed Brown   Input Parameters:
3629b5a892a1SMatthew G. Knepley + dm      - The DMPlex
3630b5a892a1SMatthew G. Knepley . p       - The mesh point
36316b867d5aSJose E. Roman - useCone - PETSC_TRUE for the closure, otherwise return the star
3632552f7358SJed Brown 
36336b867d5aSJose E. Roman   Input/Output Parameter:
36346b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
36356b867d5aSJose E. Roman            if NULL on input, internal storage will be returned, otherwise the provided array is used
36366b867d5aSJose E. Roman 
36376b867d5aSJose E. Roman   Output Parameter:
36386b867d5aSJose E. Roman . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3639552f7358SJed Brown 
3640552f7358SJed Brown   Note:
36410298fd71SBarry Smith   If using internal storage (points is NULL on input), each call overwrites the last output.
3642552f7358SJed Brown 
36433813dfbdSMatthew G Knepley   Fortran Notes:
3644b5a892a1SMatthew G. Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
36453813dfbdSMatthew G Knepley 
36463813dfbdSMatthew G Knepley   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
36473813dfbdSMatthew G Knepley 
3648552f7358SJed Brown   Level: beginner
3649552f7358SJed Brown 
3650db781477SPatrick Sanan .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3651552f7358SJed Brown @*/
3652552f7358SJed Brown PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3653552f7358SJed Brown {
3654b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3655552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3656b5a892a1SMatthew G. Knepley   if (numPoints) PetscValidIntPointer(numPoints, 4);
3657b5a892a1SMatthew G. Knepley   if (points)    PetscValidPointer(points, 5);
36589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
36599bf0dad6SMatthew G. Knepley   PetscFunctionReturn(0);
36609bf0dad6SMatthew G. Knepley }
36619bf0dad6SMatthew G. Knepley 
3662552f7358SJed Brown /*@C
3663eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3664552f7358SJed Brown 
3665552f7358SJed Brown   Not collective
3666552f7358SJed Brown 
3667552f7358SJed Brown   Input Parameters:
3668b5a892a1SMatthew G. Knepley + dm        - The DMPlex
3669b5a892a1SMatthew G. Knepley . p         - The mesh point
3670b5a892a1SMatthew G. Knepley . useCone   - PETSC_TRUE for the closure, otherwise return the star
3671b5a892a1SMatthew G. Knepley . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3672b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3673552f7358SJed Brown 
3674552f7358SJed Brown   Note:
36750298fd71SBarry Smith   If not using internal storage (points is not NULL on input), this call is unnecessary
3676552f7358SJed Brown 
36773813dfbdSMatthew G Knepley   Fortran Notes:
3678b5a892a1SMatthew G. Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
36793813dfbdSMatthew G Knepley 
36803813dfbdSMatthew G Knepley   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
36813813dfbdSMatthew G Knepley 
3682552f7358SJed Brown   Level: beginner
3683552f7358SJed Brown 
3684db781477SPatrick Sanan .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3685552f7358SJed Brown @*/
3686552f7358SJed Brown PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3687552f7358SJed Brown {
3688b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3689552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36904ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
36919566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
3692552f7358SJed Brown   PetscFunctionReturn(0);
3693552f7358SJed Brown }
3694552f7358SJed Brown 
3695552f7358SJed Brown /*@
3696eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3697552f7358SJed Brown 
3698552f7358SJed Brown   Not collective
3699552f7358SJed Brown 
3700552f7358SJed Brown   Input Parameter:
3701552f7358SJed Brown . mesh - The DMPlex
3702552f7358SJed Brown 
3703552f7358SJed Brown   Output Parameters:
3704552f7358SJed Brown + maxConeSize - The maximum number of in-edges
3705552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
3706552f7358SJed Brown 
3707552f7358SJed Brown   Level: beginner
3708552f7358SJed Brown 
3709db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3710552f7358SJed Brown @*/
3711552f7358SJed Brown PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3712552f7358SJed Brown {
3713552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
3714552f7358SJed Brown 
3715552f7358SJed Brown   PetscFunctionBegin;
3716552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37176302a7fbSVaclav Hapla   if (maxConeSize) {
37186302a7fbSVaclav Hapla     PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
37196302a7fbSVaclav Hapla   }
37206302a7fbSVaclav Hapla   if (maxSupportSize) {
37216302a7fbSVaclav Hapla     PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
37226302a7fbSVaclav Hapla   }
3723552f7358SJed Brown   PetscFunctionReturn(0);
3724552f7358SJed Brown }
3725552f7358SJed Brown 
3726552f7358SJed Brown PetscErrorCode DMSetUp_Plex(DM dm)
3727552f7358SJed Brown {
3728552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
37296302a7fbSVaclav Hapla   PetscInt       size, maxSupportSize;
3730552f7358SJed Brown 
3731552f7358SJed Brown   PetscFunctionBegin;
3732552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
37349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
37359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
37369566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
37379566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt)));
37386302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
37396302a7fbSVaclav Hapla   if (maxSupportSize) {
37409566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
37419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
37429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
37439566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt)));
3744552f7358SJed Brown   }
3745552f7358SJed Brown   PetscFunctionReturn(0);
3746552f7358SJed Brown }
3747552f7358SJed Brown 
3748276c5506SMatthew G. Knepley PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3749552f7358SJed Brown {
3750552f7358SJed Brown   PetscFunctionBegin;
37519566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
37529566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3753c2939958SSatish Balay   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3754736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
3755f94b4a02SBlaise Bourdin     PetscSF        sfMigrationInv,sfNatural;
3756f94b4a02SBlaise Bourdin     PetscSection   section, sectionSeq;
3757f94b4a02SBlaise Bourdin 
37583dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
37599566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject) dm->sfMigration));
37609566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection((*subdm), &section));
37619566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv));
37629566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq));
37639566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq));
3764f94b4a02SBlaise Bourdin 
37659566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural));
3766c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
37679566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&sectionSeq));
37689566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sfMigrationInv));
3769f94b4a02SBlaise Bourdin   }
3770552f7358SJed Brown   PetscFunctionReturn(0);
3771552f7358SJed Brown }
3772552f7358SJed Brown 
37732adcc780SMatthew G. Knepley PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
37742adcc780SMatthew G. Knepley {
37753dcd263cSBlaise Bourdin   PetscInt       i = 0;
37762adcc780SMatthew G. Knepley 
37772adcc780SMatthew G. Knepley   PetscFunctionBegin;
37789566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
37799566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
3780c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
37813dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
37823dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
37833dcd263cSBlaise Bourdin       PetscSF        sfMigrationInv,sfNatural;
37843dcd263cSBlaise Bourdin       PetscSection   section, sectionSeq;
37853dcd263cSBlaise Bourdin 
37863dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
37879566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration));
3788c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
37899566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection((*superdm), &section));
37909566063dSJacob Faibussowitsch       PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv));
37919566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq));
37929566063dSJacob Faibussowitsch       PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq));
37933dcd263cSBlaise Bourdin 
37949566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural));
3795c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
37969566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&sectionSeq));
37979566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sfMigrationInv));
37983dcd263cSBlaise Bourdin       break;
37993dcd263cSBlaise Bourdin     }
38003dcd263cSBlaise Bourdin   }
38012adcc780SMatthew G. Knepley   PetscFunctionReturn(0);
38022adcc780SMatthew G. Knepley }
38032adcc780SMatthew G. Knepley 
3804552f7358SJed Brown /*@
3805eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3806552f7358SJed Brown 
3807552f7358SJed Brown   Not collective
3808552f7358SJed Brown 
3809552f7358SJed Brown   Input Parameter:
3810552f7358SJed Brown . mesh - The DMPlex
3811552f7358SJed Brown 
3812552f7358SJed Brown   Output Parameter:
3813552f7358SJed Brown 
3814552f7358SJed Brown   Note:
3815552f7358SJed Brown   This should be called after all calls to DMPlexSetCone()
3816552f7358SJed Brown 
3817552f7358SJed Brown   Level: beginner
3818552f7358SJed Brown 
3819db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
3820552f7358SJed Brown @*/
3821552f7358SJed Brown PetscErrorCode DMPlexSymmetrize(DM dm)
3822552f7358SJed Brown {
3823552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
3824552f7358SJed Brown   PetscInt      *offsets;
3825552f7358SJed Brown   PetscInt       supportSize;
3826552f7358SJed Brown   PetscInt       pStart, pEnd, p;
3827552f7358SJed Brown 
3828552f7358SJed Brown   PetscFunctionBegin;
3829552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
383028b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
38319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0));
3832552f7358SJed Brown   /* Calculate support sizes */
38339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3834552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
3835552f7358SJed Brown     PetscInt dof, off, c;
3836552f7358SJed Brown 
38379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
38389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3839552f7358SJed Brown     for (c = off; c < off+dof; ++c) {
38409566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
3841552f7358SJed Brown     }
3842552f7358SJed Brown   }
38439566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
3844552f7358SJed Brown   /* Calculate supports */
38459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
38469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
38479566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
3848552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
3849552f7358SJed Brown     PetscInt dof, off, c;
3850552f7358SJed Brown 
38519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
38529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3853552f7358SJed Brown     for (c = off; c < off+dof; ++c) {
3854552f7358SJed Brown       const PetscInt q = mesh->cones[c];
3855552f7358SJed Brown       PetscInt       offS;
3856552f7358SJed Brown 
38579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
38580d644c17SKarl Rupp 
3859552f7358SJed Brown       mesh->supports[offS+offsets[q]] = p;
3860552f7358SJed Brown       ++offsets[q];
3861552f7358SJed Brown     }
3862552f7358SJed Brown   }
38639566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
38649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0));
3865552f7358SJed Brown   PetscFunctionReturn(0);
3866552f7358SJed Brown }
3867552f7358SJed Brown 
3868277ea44aSLisandro Dalcin static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3869277ea44aSLisandro Dalcin {
3870277ea44aSLisandro Dalcin   IS             stratumIS;
3871277ea44aSLisandro Dalcin 
3872277ea44aSLisandro Dalcin   PetscFunctionBegin;
3873277ea44aSLisandro Dalcin   if (pStart >= pEnd) PetscFunctionReturn(0);
387476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3875277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
3876277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
38779566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
3878277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
38799566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
3880277ea44aSLisandro Dalcin       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3881277ea44aSLisandro Dalcin     }
388263a3b9bcSJacob 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);
3883277ea44aSLisandro Dalcin   }
38849566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS));
38859566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
38869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
3887277ea44aSLisandro Dalcin   PetscFunctionReturn(0);
3888277ea44aSLisandro Dalcin }
3889277ea44aSLisandro Dalcin 
3890552f7358SJed Brown /*@
3891a8d69d7bSBarry Smith   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
38926dd80730SBarry Smith   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3893552f7358SJed Brown   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3894552f7358SJed Brown   the DAG.
3895552f7358SJed Brown 
3896bf4602e4SToby Isaac   Collective on dm
3897552f7358SJed Brown 
3898552f7358SJed Brown   Input Parameter:
3899552f7358SJed Brown . mesh - The DMPlex
3900552f7358SJed Brown 
3901552f7358SJed Brown   Output Parameter:
3902552f7358SJed Brown 
3903552f7358SJed Brown   Notes:
3904b1bb481bSMatthew Knepley   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3905b1bb481bSMatthew 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
3906b1bb481bSMatthew Knepley   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3907c58f1c22SToby Isaac   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3908150b719bSJed Brown   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3909552f7358SJed Brown 
3910b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3911b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3912b1bb481bSMatthew 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
3913b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
3914b1bb481bSMatthew Knepley $  cone(c0) = {e0, v2}
3915b1bb481bSMatthew Knepley $  cone(e0) = {v0, v1}
3916b1bb481bSMatthew Knepley   If DMPlexStratify() is run on this mesh, it will give depths
3917b1bb481bSMatthew Knepley $  depth 0 = {v0, v1, v2}
3918b1bb481bSMatthew Knepley $  depth 1 = {e0, c0}
3919b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3920b1bb481bSMatthew Knepley 
3921150b719bSJed Brown   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3922552f7358SJed Brown 
3923552f7358SJed Brown   Level: beginner
3924552f7358SJed Brown 
3925db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
3926552f7358SJed Brown @*/
3927552f7358SJed Brown PetscErrorCode DMPlexStratify(DM dm)
3928552f7358SJed Brown {
3929df0420ecSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
3930aa50250dSMatthew G. Knepley   DMLabel        label;
3931552f7358SJed Brown   PetscInt       pStart, pEnd, p;
3932552f7358SJed Brown   PetscInt       numRoots = 0, numLeaves = 0;
3933552f7358SJed Brown 
3934552f7358SJed Brown   PetscFunctionBegin;
3935552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
39369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0));
3937277ea44aSLisandro Dalcin 
3938277ea44aSLisandro Dalcin   /* Create depth label */
39399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
39409566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
39419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
3942277ea44aSLisandro Dalcin 
3943277ea44aSLisandro Dalcin   {
3944552f7358SJed Brown     /* Initialize roots and count leaves */
3945277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
3946277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
3947552f7358SJed Brown     PetscInt coneSize, supportSize;
3948552f7358SJed Brown 
3949277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
39509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
39519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
3952552f7358SJed Brown       if (!coneSize && supportSize) {
3953277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
3954277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
3955552f7358SJed Brown         ++numRoots;
3956552f7358SJed Brown       } else if (!supportSize && coneSize) {
3957552f7358SJed Brown         ++numLeaves;
3958552f7358SJed Brown       } else if (!supportSize && !coneSize) {
3959552f7358SJed Brown         /* Isolated points */
3960277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
3961277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
3962552f7358SJed Brown       }
3963552f7358SJed Brown     }
39649566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1));
3965277ea44aSLisandro Dalcin   }
3966277ea44aSLisandro Dalcin 
3967552f7358SJed Brown   if (numRoots + numLeaves == (pEnd - pStart)) {
3968277ea44aSLisandro Dalcin     PetscInt sMin = PETSC_MAX_INT;
3969277ea44aSLisandro Dalcin     PetscInt sMax = PETSC_MIN_INT;
3970552f7358SJed Brown     PetscInt coneSize, supportSize;
3971552f7358SJed Brown 
3972277ea44aSLisandro Dalcin     for (p = pStart; p < pEnd; ++p) {
39739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
39749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
3975552f7358SJed Brown       if (!supportSize && coneSize) {
3976277ea44aSLisandro Dalcin         sMin = PetscMin(p, sMin);
3977277ea44aSLisandro Dalcin         sMax = PetscMax(p, sMax);
3978552f7358SJed Brown       }
3979552f7358SJed Brown     }
39809566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1));
3981552f7358SJed Brown   } else {
3982277ea44aSLisandro Dalcin     PetscInt level = 0;
3983277ea44aSLisandro Dalcin     PetscInt qStart, qEnd, q;
3984552f7358SJed Brown 
39859566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
3986277ea44aSLisandro Dalcin     while (qEnd > qStart) {
3987277ea44aSLisandro Dalcin       PetscInt sMin = PETSC_MAX_INT;
3988277ea44aSLisandro Dalcin       PetscInt sMax = PETSC_MIN_INT;
398974ef644bSMatthew G. Knepley 
3990277ea44aSLisandro Dalcin       for (q = qStart; q < qEnd; ++q) {
399174ef644bSMatthew G. Knepley         const PetscInt *support;
399274ef644bSMatthew G. Knepley         PetscInt        supportSize, s;
399374ef644bSMatthew G. Knepley 
39949566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
39959566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, q, &support));
399674ef644bSMatthew G. Knepley         for (s = 0; s < supportSize; ++s) {
3997277ea44aSLisandro Dalcin           sMin = PetscMin(support[s], sMin);
3998277ea44aSLisandro Dalcin           sMax = PetscMax(support[s], sMax);
3999552f7358SJed Brown         }
4000552f7358SJed Brown       }
40019566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &level));
40029566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1));
40039566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
400474ef644bSMatthew G. Knepley     }
400574ef644bSMatthew G. Knepley   }
4006bf4602e4SToby Isaac   { /* just in case there is an empty process */
4007bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4008bf4602e4SToby Isaac 
40099566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
40109566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
4011bf4602e4SToby Isaac     for (v = numValues; v < maxValues; v++) {
40129566063dSJacob Faibussowitsch       PetscCall(DMLabelAddStratum(label, v));
4013bf4602e4SToby Isaac     }
4014bf4602e4SToby Isaac   }
40159566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState));
40169566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0));
4017552f7358SJed Brown   PetscFunctionReturn(0);
4018552f7358SJed Brown }
4019552f7358SJed Brown 
4020412e9a14SMatthew G. Knepley PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4021ba2698f1SMatthew G. Knepley {
4022412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4023412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4024ba2698f1SMatthew G. Knepley 
4025412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
40269566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
40279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
40289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4029ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4030ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4031ba2698f1SMatthew G. Knepley     switch (pdepth) {
4032ba2698f1SMatthew G. Knepley       case 0: ct = DM_POLYTOPE_POINT;break;
4033ba2698f1SMatthew G. Knepley       case 1:
4034ba2698f1SMatthew G. Knepley         switch (coneSize) {
4035ba2698f1SMatthew G. Knepley           case 2: ct = DM_POLYTOPE_SEGMENT;break;
4036ba2698f1SMatthew G. Knepley           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4037ba2698f1SMatthew G. Knepley           case 4:
4038ba2698f1SMatthew G. Knepley           switch (dim) {
4039ba2698f1SMatthew G. Knepley             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
4040ba2698f1SMatthew G. Knepley             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
4041ba2698f1SMatthew G. Knepley             default: break;
4042ba2698f1SMatthew G. Knepley           }
4043ba2698f1SMatthew G. Knepley           break;
4044da9060c4SMatthew G. Knepley         case 5: ct = DM_POLYTOPE_PYRAMID;break;
4045ba2698f1SMatthew G. Knepley         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4046ba2698f1SMatthew G. Knepley         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
4047ba2698f1SMatthew G. Knepley         default: break;
4048ba2698f1SMatthew G. Knepley       }
4049ba2698f1SMatthew G. Knepley     }
4050ba2698f1SMatthew G. Knepley   } else {
4051ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4052ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4053ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4054ba2698f1SMatthew G. Knepley       switch (dim) {
4055ba2698f1SMatthew G. Knepley         case 1:
4056ba2698f1SMatthew G. Knepley           switch (coneSize) {
4057ba2698f1SMatthew G. Knepley             case 2: ct = DM_POLYTOPE_SEGMENT;break;
4058ba2698f1SMatthew G. Knepley             default: break;
4059ba2698f1SMatthew G. Knepley           }
4060ba2698f1SMatthew G. Knepley           break;
4061ba2698f1SMatthew G. Knepley         case 2:
4062ba2698f1SMatthew G. Knepley           switch (coneSize) {
4063ba2698f1SMatthew G. Knepley             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4064ba2698f1SMatthew G. Knepley             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4065ba2698f1SMatthew G. Knepley             default: break;
4066ba2698f1SMatthew G. Knepley           }
4067ba2698f1SMatthew G. Knepley           break;
4068ba2698f1SMatthew G. Knepley         case 3:
4069ba2698f1SMatthew G. Knepley           switch (coneSize) {
4070ba2698f1SMatthew G. Knepley             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
4071da9060c4SMatthew G. Knepley             case 5:
4072da9060c4SMatthew G. Knepley             {
4073da9060c4SMatthew G. Knepley               const PetscInt *cone;
4074da9060c4SMatthew G. Knepley               PetscInt        faceConeSize;
4075da9060c4SMatthew G. Knepley 
40769566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCone(dm, p, &cone));
40779566063dSJacob Faibussowitsch               PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4078da9060c4SMatthew G. Knepley               switch (faceConeSize) {
4079da9060c4SMatthew G. Knepley                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4080da9060c4SMatthew G. Knepley                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
4081da9060c4SMatthew G. Knepley               }
4082da9060c4SMatthew G. Knepley             }
4083da9060c4SMatthew G. Knepley             break;
4084ba2698f1SMatthew G. Knepley             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
4085ba2698f1SMatthew G. Knepley             default: break;
4086ba2698f1SMatthew G. Knepley           }
4087ba2698f1SMatthew G. Knepley           break;
4088ba2698f1SMatthew G. Knepley         default: break;
4089ba2698f1SMatthew G. Knepley       }
4090ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4091ba2698f1SMatthew G. Knepley       switch (coneSize) {
4092ba2698f1SMatthew G. Knepley         case 2: ct = DM_POLYTOPE_SEGMENT;break;
4093ba2698f1SMatthew G. Knepley         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4094ba2698f1SMatthew G. Knepley         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4095ba2698f1SMatthew G. Knepley         default: break;
4096ba2698f1SMatthew G. Knepley       }
4097ba2698f1SMatthew G. Knepley     }
4098ba2698f1SMatthew G. Knepley   }
4099412e9a14SMatthew G. Knepley   *pt = ct;
4100412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
4101ba2698f1SMatthew G. Knepley }
4102412e9a14SMatthew G. Knepley 
4103412e9a14SMatthew G. Knepley /*@
4104412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4105412e9a14SMatthew G. Knepley 
4106412e9a14SMatthew G. Knepley   Collective on dm
4107412e9a14SMatthew G. Knepley 
4108412e9a14SMatthew G. Knepley   Input Parameter:
4109412e9a14SMatthew G. Knepley . mesh - The DMPlex
4110412e9a14SMatthew G. Knepley 
4111412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4112412e9a14SMatthew G. Knepley 
4113412e9a14SMatthew G. Knepley   Level: developer
4114412e9a14SMatthew G. Knepley 
4115412e9a14SMatthew G. Knepley   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4116412e9a14SMatthew G. Knepley   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4117412e9a14SMatthew G. Knepley   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4118412e9a14SMatthew G. Knepley 
4119db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4120412e9a14SMatthew G. Knepley @*/
4121412e9a14SMatthew G. Knepley PetscErrorCode DMPlexComputeCellTypes(DM dm)
4122412e9a14SMatthew G. Knepley {
4123412e9a14SMatthew G. Knepley   DM_Plex       *mesh;
4124412e9a14SMatthew G. Knepley   DMLabel        ctLabel;
4125412e9a14SMatthew G. Knepley   PetscInt       pStart, pEnd, p;
4126412e9a14SMatthew G. Knepley 
4127412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4128412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4129412e9a14SMatthew G. Knepley   mesh = (DM_Plex *) dm->data;
41309566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
41319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
41329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4133412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4134327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4135412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4136412e9a14SMatthew G. Knepley 
41379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
41389566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
413963a3b9bcSJacob Faibussowitsch     PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p);
41409566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4141412e9a14SMatthew G. Knepley   }
41429566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState));
41439566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view"));
4144ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4145ba2698f1SMatthew G. Knepley }
4146ba2698f1SMatthew G. Knepley 
4147552f7358SJed Brown /*@C
4148552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4149552f7358SJed Brown 
4150552f7358SJed Brown   Not Collective
4151552f7358SJed Brown 
4152552f7358SJed Brown   Input Parameters:
4153552f7358SJed Brown + dm - The DMPlex object
4154552f7358SJed Brown . numPoints - The number of input points for the join
4155552f7358SJed Brown - points - The input points
4156552f7358SJed Brown 
4157552f7358SJed Brown   Output Parameters:
4158552f7358SJed Brown + numCoveredPoints - The number of points in the join
4159552f7358SJed Brown - coveredPoints - The points in the join
4160552f7358SJed Brown 
4161552f7358SJed Brown   Level: intermediate
4162552f7358SJed Brown 
4163552f7358SJed Brown   Note: Currently, this is restricted to a single level join
4164552f7358SJed Brown 
41653813dfbdSMatthew G Knepley   Fortran Notes:
41663813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
41673813dfbdSMatthew G Knepley   include petsc.h90 in your code.
41683813dfbdSMatthew G Knepley 
41693813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
41703813dfbdSMatthew G Knepley 
4171db781477SPatrick Sanan .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4172552f7358SJed Brown @*/
4173552f7358SJed Brown PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4174552f7358SJed Brown {
4175552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
4176552f7358SJed Brown   PetscInt      *join[2];
4177552f7358SJed Brown   PetscInt       joinSize, i = 0;
4178552f7358SJed Brown   PetscInt       dof, off, p, c, m;
41796302a7fbSVaclav Hapla   PetscInt       maxSupportSize;
4180552f7358SJed Brown 
4181552f7358SJed Brown   PetscFunctionBegin;
4182552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
418348bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
418448bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
418548bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
41866302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
41876302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
41886302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4189552f7358SJed Brown   /* Copy in support of first point */
41909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
41919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4192552f7358SJed Brown   for (joinSize = 0; joinSize < dof; ++joinSize) {
4193552f7358SJed Brown     join[i][joinSize] = mesh->supports[off+joinSize];
4194552f7358SJed Brown   }
4195552f7358SJed Brown   /* Check each successive support */
4196552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4197552f7358SJed Brown     PetscInt newJoinSize = 0;
4198552f7358SJed Brown 
41999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
42009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4201552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4202552f7358SJed Brown       const PetscInt point = mesh->supports[off+c];
4203552f7358SJed Brown 
4204552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4205552f7358SJed Brown         if (point == join[i][m]) {
4206552f7358SJed Brown           join[1-i][newJoinSize++] = point;
4207552f7358SJed Brown           break;
4208552f7358SJed Brown         }
4209552f7358SJed Brown       }
4210552f7358SJed Brown     }
4211552f7358SJed Brown     joinSize = newJoinSize;
4212552f7358SJed Brown     i        = 1-i;
4213552f7358SJed Brown   }
4214552f7358SJed Brown   *numCoveredPoints = joinSize;
4215552f7358SJed Brown   *coveredPoints    = join[i];
42166302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i]));
4217552f7358SJed Brown   PetscFunctionReturn(0);
4218552f7358SJed Brown }
4219552f7358SJed Brown 
4220552f7358SJed Brown /*@C
4221552f7358SJed Brown   DMPlexRestoreJoin - Restore an array for the join of the set of points
4222552f7358SJed Brown 
4223552f7358SJed Brown   Not Collective
4224552f7358SJed Brown 
4225552f7358SJed Brown   Input Parameters:
4226552f7358SJed Brown + dm - The DMPlex object
4227552f7358SJed Brown . numPoints - The number of input points for the join
4228552f7358SJed Brown - points - The input points
4229552f7358SJed Brown 
4230552f7358SJed Brown   Output Parameters:
4231552f7358SJed Brown + numCoveredPoints - The number of points in the join
4232552f7358SJed Brown - coveredPoints - The points in the join
4233552f7358SJed Brown 
42343813dfbdSMatthew G Knepley   Fortran Notes:
42353813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
42363813dfbdSMatthew G Knepley   include petsc.h90 in your code.
42373813dfbdSMatthew G Knepley 
42383813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
42393813dfbdSMatthew G Knepley 
4240552f7358SJed Brown   Level: intermediate
4241552f7358SJed Brown 
4242db781477SPatrick Sanan .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4243552f7358SJed Brown @*/
4244552f7358SJed Brown PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4245552f7358SJed Brown {
4246552f7358SJed Brown   PetscFunctionBegin;
4247552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4248d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points,3);
4249d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4250d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints, 5);
42519566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints));
4252d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
4253552f7358SJed Brown   PetscFunctionReturn(0);
4254552f7358SJed Brown }
4255552f7358SJed Brown 
4256552f7358SJed Brown /*@C
4257552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4258552f7358SJed Brown 
4259552f7358SJed Brown   Not Collective
4260552f7358SJed Brown 
4261552f7358SJed Brown   Input Parameters:
4262552f7358SJed Brown + dm - The DMPlex object
4263552f7358SJed Brown . numPoints - The number of input points for the join
4264552f7358SJed Brown - points - The input points
4265552f7358SJed Brown 
4266552f7358SJed Brown   Output Parameters:
4267552f7358SJed Brown + numCoveredPoints - The number of points in the join
4268552f7358SJed Brown - coveredPoints - The points in the join
4269552f7358SJed Brown 
42703813dfbdSMatthew G Knepley   Fortran Notes:
42713813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
42723813dfbdSMatthew G Knepley   include petsc.h90 in your code.
42733813dfbdSMatthew G Knepley 
42743813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
42753813dfbdSMatthew G Knepley 
4276552f7358SJed Brown   Level: intermediate
4277552f7358SJed Brown 
4278db781477SPatrick Sanan .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4279552f7358SJed Brown @*/
4280552f7358SJed Brown PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4281552f7358SJed Brown {
4282552f7358SJed Brown   PetscInt      *offsets, **closures;
4283552f7358SJed Brown   PetscInt      *join[2];
4284552f7358SJed Brown   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
428524c766afSToby Isaac   PetscInt       p, d, c, m, ms;
4286552f7358SJed Brown 
4287552f7358SJed Brown   PetscFunctionBegin;
4288552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
428948bb261cSVaclav Hapla   PetscValidIntPointer(points, 3);
429048bb261cSVaclav Hapla   PetscValidIntPointer(numCoveredPoints, 4);
429148bb261cSVaclav Hapla   PetscValidPointer(coveredPoints, 5);
4292552f7358SJed Brown 
42939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
42949566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
42959566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets));
42966302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
429724c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
42989566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
42999566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4300552f7358SJed Brown 
4301552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4302552f7358SJed Brown     PetscInt closureSize;
4303552f7358SJed Brown 
43049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
43050d644c17SKarl Rupp 
4306552f7358SJed Brown     offsets[p*(depth+2)+0] = 0;
4307552f7358SJed Brown     for (d = 0; d < depth+1; ++d) {
4308552f7358SJed Brown       PetscInt pStart, pEnd, i;
4309552f7358SJed Brown 
43109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4311552f7358SJed Brown       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
4312552f7358SJed Brown         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4313552f7358SJed Brown           offsets[p*(depth+2)+d+1] = i;
4314552f7358SJed Brown           break;
4315552f7358SJed Brown         }
4316552f7358SJed Brown       }
4317552f7358SJed Brown       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
4318552f7358SJed Brown     }
431963a3b9bcSJacob 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);
4320552f7358SJed Brown   }
4321552f7358SJed Brown   for (d = 0; d < depth+1; ++d) {
4322552f7358SJed Brown     PetscInt dof;
4323552f7358SJed Brown 
4324552f7358SJed Brown     /* Copy in support of first point */
4325552f7358SJed Brown     dof = offsets[d+1] - offsets[d];
4326552f7358SJed Brown     for (joinSize = 0; joinSize < dof; ++joinSize) {
4327552f7358SJed Brown       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
4328552f7358SJed Brown     }
4329552f7358SJed Brown     /* Check each successive cone */
4330552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4331552f7358SJed Brown       PetscInt newJoinSize = 0;
4332552f7358SJed Brown 
4333552f7358SJed Brown       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
4334552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4335552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
4336552f7358SJed Brown 
4337552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4338552f7358SJed Brown           if (point == join[i][m]) {
4339552f7358SJed Brown             join[1-i][newJoinSize++] = point;
4340552f7358SJed Brown             break;
4341552f7358SJed Brown           }
4342552f7358SJed Brown         }
4343552f7358SJed Brown       }
4344552f7358SJed Brown       joinSize = newJoinSize;
4345552f7358SJed Brown       i        = 1-i;
4346552f7358SJed Brown     }
4347552f7358SJed Brown     if (joinSize) break;
4348552f7358SJed Brown   }
4349552f7358SJed Brown   *numCoveredPoints = joinSize;
4350552f7358SJed Brown   *coveredPoints    = join[i];
4351552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
43529566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4353552f7358SJed Brown   }
43549566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
43559566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets));
43566302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i]));
4357552f7358SJed Brown   PetscFunctionReturn(0);
4358552f7358SJed Brown }
4359552f7358SJed Brown 
4360552f7358SJed Brown /*@C
4361552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4362552f7358SJed Brown 
4363552f7358SJed Brown   Not Collective
4364552f7358SJed Brown 
4365552f7358SJed Brown   Input Parameters:
4366552f7358SJed Brown + dm - The DMPlex object
4367552f7358SJed Brown . numPoints - The number of input points for the meet
4368552f7358SJed Brown - points - The input points
4369552f7358SJed Brown 
4370552f7358SJed Brown   Output Parameters:
4371552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4372552f7358SJed Brown - coveredPoints - The points in the meet
4373552f7358SJed Brown 
4374552f7358SJed Brown   Level: intermediate
4375552f7358SJed Brown 
4376552f7358SJed Brown   Note: Currently, this is restricted to a single level meet
4377552f7358SJed Brown 
43783813dfbdSMatthew G Knepley   Fortran Notes:
43793813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
43803813dfbdSMatthew G Knepley   include petsc.h90 in your code.
43813813dfbdSMatthew G Knepley 
43823813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
43833813dfbdSMatthew G Knepley 
4384db781477SPatrick Sanan .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4385552f7358SJed Brown @*/
4386552f7358SJed Brown PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4387552f7358SJed Brown {
4388552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
4389552f7358SJed Brown   PetscInt      *meet[2];
4390552f7358SJed Brown   PetscInt       meetSize, i = 0;
4391552f7358SJed Brown   PetscInt       dof, off, p, c, m;
43926302a7fbSVaclav Hapla   PetscInt       maxConeSize;
4393552f7358SJed Brown 
4394552f7358SJed Brown   PetscFunctionBegin;
4395552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4396dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4397dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveringPoints, 4);
4398064a246eSJacob Faibussowitsch   PetscValidPointer(coveringPoints, 5);
43996302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
44006302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
44016302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4402552f7358SJed Brown   /* Copy in cone of first point */
44039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
44049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4405552f7358SJed Brown   for (meetSize = 0; meetSize < dof; ++meetSize) {
4406552f7358SJed Brown     meet[i][meetSize] = mesh->cones[off+meetSize];
4407552f7358SJed Brown   }
4408552f7358SJed Brown   /* Check each successive cone */
4409552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4410552f7358SJed Brown     PetscInt newMeetSize = 0;
4411552f7358SJed Brown 
44129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
44139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4414552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4415552f7358SJed Brown       const PetscInt point = mesh->cones[off+c];
4416552f7358SJed Brown 
4417552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
4418552f7358SJed Brown         if (point == meet[i][m]) {
4419552f7358SJed Brown           meet[1-i][newMeetSize++] = point;
4420552f7358SJed Brown           break;
4421552f7358SJed Brown         }
4422552f7358SJed Brown       }
4423552f7358SJed Brown     }
4424552f7358SJed Brown     meetSize = newMeetSize;
4425552f7358SJed Brown     i        = 1-i;
4426552f7358SJed Brown   }
4427552f7358SJed Brown   *numCoveringPoints = meetSize;
4428552f7358SJed Brown   *coveringPoints    = meet[i];
44296302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i]));
4430552f7358SJed Brown   PetscFunctionReturn(0);
4431552f7358SJed Brown }
4432552f7358SJed Brown 
4433552f7358SJed Brown /*@C
4434552f7358SJed Brown   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4435552f7358SJed Brown 
4436552f7358SJed Brown   Not Collective
4437552f7358SJed Brown 
4438552f7358SJed Brown   Input Parameters:
4439552f7358SJed Brown + dm - The DMPlex object
4440552f7358SJed Brown . numPoints - The number of input points for the meet
4441552f7358SJed Brown - points - The input points
4442552f7358SJed Brown 
4443552f7358SJed Brown   Output Parameters:
4444552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4445552f7358SJed Brown - coveredPoints - The points in the meet
4446552f7358SJed Brown 
4447552f7358SJed Brown   Level: intermediate
4448552f7358SJed Brown 
44493813dfbdSMatthew G Knepley   Fortran Notes:
44503813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
44513813dfbdSMatthew G Knepley   include petsc.h90 in your code.
44523813dfbdSMatthew G Knepley 
44533813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
44543813dfbdSMatthew G Knepley 
4455db781477SPatrick Sanan .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4456552f7358SJed Brown @*/
4457552f7358SJed Brown PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4458552f7358SJed Brown {
4459552f7358SJed Brown   PetscFunctionBegin;
4460552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4461d7902bd2SMatthew G. Knepley   if (points) PetscValidIntPointer(points,3);
4462d7902bd2SMatthew G. Knepley   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4463d7902bd2SMatthew G. Knepley   PetscValidPointer(coveredPoints,5);
44649566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints));
4465d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
4466552f7358SJed Brown   PetscFunctionReturn(0);
4467552f7358SJed Brown }
4468552f7358SJed Brown 
4469552f7358SJed Brown /*@C
4470552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
4471552f7358SJed Brown 
4472552f7358SJed Brown   Not Collective
4473552f7358SJed Brown 
4474552f7358SJed Brown   Input Parameters:
4475552f7358SJed Brown + dm - The DMPlex object
4476552f7358SJed Brown . numPoints - The number of input points for the meet
4477552f7358SJed Brown - points - The input points
4478552f7358SJed Brown 
4479552f7358SJed Brown   Output Parameters:
4480552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4481552f7358SJed Brown - coveredPoints - The points in the meet
4482552f7358SJed Brown 
4483552f7358SJed Brown   Level: intermediate
4484552f7358SJed Brown 
44853813dfbdSMatthew G Knepley   Fortran Notes:
44863813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
44873813dfbdSMatthew G Knepley   include petsc.h90 in your code.
44883813dfbdSMatthew G Knepley 
44893813dfbdSMatthew G Knepley   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
44903813dfbdSMatthew G Knepley 
4491db781477SPatrick Sanan .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4492552f7358SJed Brown @*/
4493552f7358SJed Brown PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4494552f7358SJed Brown {
4495552f7358SJed Brown   PetscInt      *offsets, **closures;
4496552f7358SJed Brown   PetscInt      *meet[2];
4497552f7358SJed Brown   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
449824c766afSToby Isaac   PetscInt       p, h, c, m, mc;
4499552f7358SJed Brown 
4500552f7358SJed Brown   PetscFunctionBegin;
4501552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4502dadcf809SJacob Faibussowitsch   PetscValidIntPointer(points, 3);
4503dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numCoveredPoints, 4);
4504064a246eSJacob Faibussowitsch   PetscValidPointer(coveredPoints, 5);
4505552f7358SJed Brown 
45069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
45079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
45089566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets));
45096302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
451024c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
45119566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
45129566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4513552f7358SJed Brown 
4514552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4515552f7358SJed Brown     PetscInt closureSize;
4516552f7358SJed Brown 
45179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
45180d644c17SKarl Rupp 
4519552f7358SJed Brown     offsets[p*(height+2)+0] = 0;
4520552f7358SJed Brown     for (h = 0; h < height+1; ++h) {
4521552f7358SJed Brown       PetscInt pStart, pEnd, i;
4522552f7358SJed Brown 
45239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4524552f7358SJed Brown       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4525552f7358SJed Brown         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4526552f7358SJed Brown           offsets[p*(height+2)+h+1] = i;
4527552f7358SJed Brown           break;
4528552f7358SJed Brown         }
4529552f7358SJed Brown       }
4530552f7358SJed Brown       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4531552f7358SJed Brown     }
453263a3b9bcSJacob 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);
4533552f7358SJed Brown   }
4534552f7358SJed Brown   for (h = 0; h < height+1; ++h) {
4535552f7358SJed Brown     PetscInt dof;
4536552f7358SJed Brown 
4537552f7358SJed Brown     /* Copy in cone of first point */
4538552f7358SJed Brown     dof = offsets[h+1] - offsets[h];
4539552f7358SJed Brown     for (meetSize = 0; meetSize < dof; ++meetSize) {
4540552f7358SJed Brown       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4541552f7358SJed Brown     }
4542552f7358SJed Brown     /* Check each successive cone */
4543552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
4544552f7358SJed Brown       PetscInt newMeetSize = 0;
4545552f7358SJed Brown 
4546552f7358SJed Brown       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4547552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4548552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4549552f7358SJed Brown 
4550552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
4551552f7358SJed Brown           if (point == meet[i][m]) {
4552552f7358SJed Brown             meet[1-i][newMeetSize++] = point;
4553552f7358SJed Brown             break;
4554552f7358SJed Brown           }
4555552f7358SJed Brown         }
4556552f7358SJed Brown       }
4557552f7358SJed Brown       meetSize = newMeetSize;
4558552f7358SJed Brown       i        = 1-i;
4559552f7358SJed Brown     }
4560552f7358SJed Brown     if (meetSize) break;
4561552f7358SJed Brown   }
4562552f7358SJed Brown   *numCoveredPoints = meetSize;
4563552f7358SJed Brown   *coveredPoints    = meet[i];
4564552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
45659566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
4566552f7358SJed Brown   }
45679566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
45689566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets));
45696302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i]));
4570552f7358SJed Brown   PetscFunctionReturn(0);
4571552f7358SJed Brown }
4572552f7358SJed Brown 
45734e3744c5SMatthew G. Knepley /*@C
45744e3744c5SMatthew G. Knepley   DMPlexEqual - Determine if two DMs have the same topology
45754e3744c5SMatthew G. Knepley 
45764e3744c5SMatthew G. Knepley   Not Collective
45774e3744c5SMatthew G. Knepley 
45784e3744c5SMatthew G. Knepley   Input Parameters:
45794e3744c5SMatthew G. Knepley + dmA - A DMPlex object
45804e3744c5SMatthew G. Knepley - dmB - A DMPlex object
45814e3744c5SMatthew G. Knepley 
45824e3744c5SMatthew G. Knepley   Output Parameters:
45834e3744c5SMatthew G. Knepley . equal - PETSC_TRUE if the topologies are identical
45844e3744c5SMatthew G. Knepley 
45854e3744c5SMatthew G. Knepley   Level: intermediate
45864e3744c5SMatthew G. Knepley 
45874e3744c5SMatthew G. Knepley   Notes:
45884e3744c5SMatthew G. Knepley   We are not solving graph isomorphism, so we do not permutation.
45894e3744c5SMatthew G. Knepley 
4590db781477SPatrick Sanan .seealso: `DMPlexGetCone()`
45914e3744c5SMatthew G. Knepley @*/
45924e3744c5SMatthew G. Knepley PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
45934e3744c5SMatthew G. Knepley {
45944e3744c5SMatthew G. Knepley   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
45954e3744c5SMatthew G. Knepley 
45964e3744c5SMatthew G. Knepley   PetscFunctionBegin;
45974e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
45984e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4599dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(equal, 3);
46004e3744c5SMatthew G. Knepley 
46014e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
46029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
46039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
46044e3744c5SMatthew G. Knepley   if (depth != depthB) PetscFunctionReturn(0);
46059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart,  &pEnd));
46069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
46074e3744c5SMatthew G. Knepley   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
46084e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
46094e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
46104e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
46114e3744c5SMatthew G. Knepley 
46129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
46139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
46149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
46159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
46169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
46179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
46184e3744c5SMatthew G. Knepley     if (coneSize != coneSizeB) PetscFunctionReturn(0);
46194e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
46204e3744c5SMatthew G. Knepley       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
46214e3744c5SMatthew G. Knepley       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
46224e3744c5SMatthew G. Knepley     }
46239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
46249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
46259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
46269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
46274e3744c5SMatthew G. Knepley     if (supportSize != supportSizeB) PetscFunctionReturn(0);
46284e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
46294e3744c5SMatthew G. Knepley       if (support[s] != supportB[s]) PetscFunctionReturn(0);
46304e3744c5SMatthew G. Knepley     }
46314e3744c5SMatthew G. Knepley   }
46324e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
46334e3744c5SMatthew G. Knepley   PetscFunctionReturn(0);
46344e3744c5SMatthew G. Knepley }
46354e3744c5SMatthew G. Knepley 
46367cd05799SMatthew G. Knepley /*@C
46377cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
46387cd05799SMatthew G. Knepley 
46397cd05799SMatthew G. Knepley   Not Collective
46407cd05799SMatthew G. Knepley 
46417cd05799SMatthew G. Knepley   Input Parameters:
46427cd05799SMatthew G. Knepley + dm         - The DMPlex
46437cd05799SMatthew G. Knepley . cellDim    - The cell dimension
46447cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
46457cd05799SMatthew G. Knepley 
46467cd05799SMatthew G. Knepley   Output Parameters:
46477cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
46487cd05799SMatthew G. Knepley 
46497cd05799SMatthew G. Knepley   Level: developer
46507cd05799SMatthew G. Knepley 
46517cd05799SMatthew G. Knepley   Notes:
46527cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
46537cd05799SMatthew G. Knepley 
4654db781477SPatrick Sanan .seealso: `DMPlexGetCone()`
46557cd05799SMatthew G. Knepley @*/
465618ad9376SMatthew G. Knepley PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4657a6dfd86eSKarl Rupp {
465882f516ccSBarry Smith   MPI_Comm       comm;
4659552f7358SJed Brown 
4660552f7358SJed Brown   PetscFunctionBegin;
46619566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
4662dadcf809SJacob Faibussowitsch   PetscValidIntPointer(numFaceVertices,4);
4663552f7358SJed Brown   switch (cellDim) {
4664552f7358SJed Brown   case 0:
4665552f7358SJed Brown     *numFaceVertices = 0;
4666552f7358SJed Brown     break;
4667552f7358SJed Brown   case 1:
4668552f7358SJed Brown     *numFaceVertices = 1;
4669552f7358SJed Brown     break;
4670552f7358SJed Brown   case 2:
4671552f7358SJed Brown     switch (numCorners) {
467219436ca2SJed Brown     case 3: /* triangle */
467319436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4674552f7358SJed Brown       break;
467519436ca2SJed Brown     case 4: /* quadrilateral */
467619436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
4677552f7358SJed Brown       break;
467819436ca2SJed Brown     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
467919436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4680552f7358SJed Brown       break;
468119436ca2SJed Brown     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
468219436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
4683552f7358SJed Brown       break;
4684552f7358SJed Brown     default:
468563a3b9bcSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4686552f7358SJed Brown     }
4687552f7358SJed Brown     break;
4688552f7358SJed Brown   case 3:
4689552f7358SJed Brown     switch (numCorners) {
469019436ca2SJed Brown     case 4: /* tetradehdron */
469119436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
4692552f7358SJed Brown       break;
469319436ca2SJed Brown     case 6: /* tet cohesive cells */
469419436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4695552f7358SJed Brown       break;
469619436ca2SJed Brown     case 8: /* hexahedron */
469719436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
4698552f7358SJed Brown       break;
469919436ca2SJed Brown     case 9: /* tet cohesive Lagrange cells */
470019436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4701552f7358SJed Brown       break;
470219436ca2SJed Brown     case 10: /* quadratic tetrahedron */
470319436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4704552f7358SJed Brown       break;
470519436ca2SJed Brown     case 12: /* hex cohesive Lagrange cells */
470619436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4707552f7358SJed Brown       break;
470819436ca2SJed Brown     case 18: /* quadratic tet cohesive Lagrange cells */
470919436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
4710552f7358SJed Brown       break;
471119436ca2SJed Brown     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
471219436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
4713552f7358SJed Brown       break;
4714552f7358SJed Brown     default:
471563a3b9bcSJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4716552f7358SJed Brown     }
4717552f7358SJed Brown     break;
4718552f7358SJed Brown   default:
471963a3b9bcSJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
4720552f7358SJed Brown   }
4721552f7358SJed Brown   PetscFunctionReturn(0);
4722552f7358SJed Brown }
4723552f7358SJed Brown 
4724552f7358SJed Brown /*@
4725aa50250dSMatthew G. Knepley   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4726552f7358SJed Brown 
4727552f7358SJed Brown   Not Collective
4728552f7358SJed Brown 
4729aa50250dSMatthew G. Knepley   Input Parameter:
4730552f7358SJed Brown . dm    - The DMPlex object
4731552f7358SJed Brown 
4732aa50250dSMatthew G. Knepley   Output Parameter:
4733aa50250dSMatthew G. Knepley . depthLabel - The DMLabel recording point depth
4734552f7358SJed Brown 
4735552f7358SJed Brown   Level: developer
4736552f7358SJed Brown 
4737db781477SPatrick Sanan .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
4738aa50250dSMatthew G. Knepley @*/
4739aa50250dSMatthew G. Knepley PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4740aa50250dSMatthew G. Knepley {
4741aa50250dSMatthew G. Knepley   PetscFunctionBegin;
4742aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4743aa50250dSMatthew G. Knepley   PetscValidPointer(depthLabel, 2);
4744c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
4745aa50250dSMatthew G. Knepley   PetscFunctionReturn(0);
4746aa50250dSMatthew G. Knepley }
4747aa50250dSMatthew G. Knepley 
4748aa50250dSMatthew G. Knepley /*@
4749aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4750aa50250dSMatthew G. Knepley 
4751aa50250dSMatthew G. Knepley   Not Collective
4752aa50250dSMatthew G. Knepley 
4753aa50250dSMatthew G. Knepley   Input Parameter:
4754aa50250dSMatthew G. Knepley . dm    - The DMPlex object
4755aa50250dSMatthew G. Knepley 
4756aa50250dSMatthew G. Knepley   Output Parameter:
4757aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
4758aa50250dSMatthew G. Knepley 
4759aa50250dSMatthew G. Knepley   Level: developer
4760552f7358SJed Brown 
4761b1bb481bSMatthew Knepley   Notes:
4762b1bb481bSMatthew Knepley   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4763dc287ab2SVaclav Hapla   The point depth is described more in detail in DMPlexGetDepthStratum().
4764dc287ab2SVaclav Hapla   An empty mesh gives -1.
4765b1bb481bSMatthew Knepley 
4766db781477SPatrick Sanan .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
4767552f7358SJed Brown @*/
4768552f7358SJed Brown PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4769552f7358SJed Brown {
4770aa50250dSMatthew G. Knepley   DMLabel        label;
4771aa50250dSMatthew G. Knepley   PetscInt       d = 0;
4772552f7358SJed Brown 
4773552f7358SJed Brown   PetscFunctionBegin;
4774552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4775dadcf809SJacob Faibussowitsch   PetscValidIntPointer(depth, 2);
47769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
47779566063dSJacob Faibussowitsch   if (label) PetscCall(DMLabelGetNumValues(label, &d));
4778552f7358SJed Brown   *depth = d-1;
4779552f7358SJed Brown   PetscFunctionReturn(0);
4780552f7358SJed Brown }
4781552f7358SJed Brown 
4782552f7358SJed Brown /*@
4783552f7358SJed Brown   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4784552f7358SJed Brown 
4785552f7358SJed Brown   Not Collective
4786552f7358SJed Brown 
4787552f7358SJed Brown   Input Parameters:
4788552f7358SJed Brown + dm    - The DMPlex object
4789570fa34dSVaclav Hapla - depth - The requested depth
4790552f7358SJed Brown 
4791552f7358SJed Brown   Output Parameters:
4792552f7358SJed Brown + start - The first point at this depth
4793552f7358SJed Brown - end   - One beyond the last point at this depth
4794552f7358SJed Brown 
4795647867b2SJed Brown   Notes:
4796647867b2SJed Brown   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4797647867b2SJed Brown   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4798647867b2SJed Brown   higher dimension, e.g., "edges".
4799647867b2SJed Brown 
4800552f7358SJed Brown   Level: developer
4801552f7358SJed Brown 
4802db781477SPatrick Sanan .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
4803552f7358SJed Brown @*/
4804570fa34dSVaclav Hapla PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
48050adebc6cSBarry Smith {
4806aa50250dSMatthew G. Knepley   DMLabel        label;
480763d1a920SMatthew G. Knepley   PetscInt       pStart, pEnd;
4808552f7358SJed Brown 
4809552f7358SJed Brown   PetscFunctionBegin;
4810552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4811dadcf809SJacob Faibussowitsch   if (start) {PetscValidIntPointer(start, 3); *start = 0;}
4812dadcf809SJacob Faibussowitsch   if (end)   {PetscValidIntPointer(end,   4); *end   = 0;}
48139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
48140d644c17SKarl Rupp   if (pStart == pEnd) PetscFunctionReturn(0);
4815570fa34dSVaclav Hapla   if (depth < 0) {
481663d1a920SMatthew G. Knepley     if (start) *start = pStart;
481763d1a920SMatthew G. Knepley     if (end)   *end   = pEnd;
481863d1a920SMatthew G. Knepley     PetscFunctionReturn(0);
4819552f7358SJed Brown   }
48209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
482128b400f6SJacob Faibussowitsch   PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4822570fa34dSVaclav Hapla   PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
4823552f7358SJed Brown   PetscFunctionReturn(0);
4824552f7358SJed Brown }
4825552f7358SJed Brown 
4826552f7358SJed Brown /*@
4827552f7358SJed Brown   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4828552f7358SJed Brown 
4829552f7358SJed Brown   Not Collective
4830552f7358SJed Brown 
4831552f7358SJed Brown   Input Parameters:
4832552f7358SJed Brown + dm     - The DMPlex object
4833570fa34dSVaclav Hapla - height - The requested height
4834552f7358SJed Brown 
4835552f7358SJed Brown   Output Parameters:
4836552f7358SJed Brown + start - The first point at this height
4837552f7358SJed Brown - end   - One beyond the last point at this height
4838552f7358SJed Brown 
4839647867b2SJed Brown   Notes:
4840647867b2SJed Brown   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4841647867b2SJed Brown   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4842647867b2SJed Brown   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4843647867b2SJed Brown 
4844552f7358SJed Brown   Level: developer
4845552f7358SJed Brown 
4846db781477SPatrick Sanan .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
4847552f7358SJed Brown @*/
4848570fa34dSVaclav Hapla PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
48490adebc6cSBarry Smith {
4850aa50250dSMatthew G. Knepley   DMLabel        label;
485163d1a920SMatthew G. Knepley   PetscInt       depth, pStart, pEnd;
4852552f7358SJed Brown 
4853552f7358SJed Brown   PetscFunctionBegin;
4854552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4855dadcf809SJacob Faibussowitsch   if (start) {PetscValidIntPointer(start, 3); *start = 0;}
4856dadcf809SJacob Faibussowitsch   if (end)   {PetscValidIntPointer(end,   4); *end   = 0;}
48579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
48580d644c17SKarl Rupp   if (pStart == pEnd) PetscFunctionReturn(0);
4859570fa34dSVaclav Hapla   if (height < 0) {
486063d1a920SMatthew G. Knepley     if (start) *start = pStart;
486163d1a920SMatthew G. Knepley     if (end)   *end   = pEnd;
486263d1a920SMatthew G. Knepley     PetscFunctionReturn(0);
4863552f7358SJed Brown   }
48649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
486528b400f6SJacob Faibussowitsch   PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
48669566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(label, &depth));
4867570fa34dSVaclav Hapla   PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end));
4868552f7358SJed Brown   PetscFunctionReturn(0);
4869552f7358SJed Brown }
4870552f7358SJed Brown 
4871ba2698f1SMatthew G. Knepley /*@
4872ba2698f1SMatthew G. Knepley   DMPlexGetPointDepth - Get the depth of a given point
4873ba2698f1SMatthew G. Knepley 
4874ba2698f1SMatthew G. Knepley   Not Collective
4875ba2698f1SMatthew G. Knepley 
4876d8d19677SJose E. Roman   Input Parameters:
4877ba2698f1SMatthew G. Knepley + dm    - The DMPlex object
4878ba2698f1SMatthew G. Knepley - point - The point
4879ba2698f1SMatthew G. Knepley 
4880ba2698f1SMatthew G. Knepley   Output Parameter:
4881ba2698f1SMatthew G. Knepley . depth - The depth of the point
4882ba2698f1SMatthew G. Knepley 
4883ba2698f1SMatthew G. Knepley   Level: intermediate
4884ba2698f1SMatthew G. Knepley 
4885db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
4886ba2698f1SMatthew G. Knepley @*/
4887ba2698f1SMatthew G. Knepley PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4888ba2698f1SMatthew G. Knepley {
4889ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
4890ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
489140a2aa30SMatthew G. Knepley   PetscValidIntPointer(depth, 3);
48929566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
4893ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4894ba2698f1SMatthew G. Knepley }
4895ba2698f1SMatthew G. Knepley 
4896ba2698f1SMatthew G. Knepley /*@
48970c0a32dcSVaclav Hapla   DMPlexGetPointHeight - Get the height of a given point
48980c0a32dcSVaclav Hapla 
48990c0a32dcSVaclav Hapla   Not Collective
49000c0a32dcSVaclav Hapla 
4901d8d19677SJose E. Roman   Input Parameters:
49020c0a32dcSVaclav Hapla + dm    - The DMPlex object
49030c0a32dcSVaclav Hapla - point - The point
49040c0a32dcSVaclav Hapla 
49050c0a32dcSVaclav Hapla   Output Parameter:
49060c0a32dcSVaclav Hapla . height - The height of the point
49070c0a32dcSVaclav Hapla 
49080c0a32dcSVaclav Hapla   Level: intermediate
49090c0a32dcSVaclav Hapla 
4910db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
49110c0a32dcSVaclav Hapla @*/
49120c0a32dcSVaclav Hapla PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
49130c0a32dcSVaclav Hapla {
49140c0a32dcSVaclav Hapla   PetscInt       n, pDepth;
49150c0a32dcSVaclav Hapla 
49160c0a32dcSVaclav Hapla   PetscFunctionBegin;
49170c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49180c0a32dcSVaclav Hapla   PetscValidIntPointer(height, 3);
49199566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
49209566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
49210c0a32dcSVaclav Hapla   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
49220c0a32dcSVaclav Hapla   PetscFunctionReturn(0);
49230c0a32dcSVaclav Hapla }
49240c0a32dcSVaclav Hapla 
49250c0a32dcSVaclav Hapla /*@
4926ba2698f1SMatthew G. Knepley   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4927ba2698f1SMatthew G. Knepley 
4928ba2698f1SMatthew G. Knepley   Not Collective
4929ba2698f1SMatthew G. Knepley 
4930ba2698f1SMatthew G. Knepley   Input Parameter:
4931ba2698f1SMatthew G. Knepley . dm - The DMPlex object
4932ba2698f1SMatthew G. Knepley 
4933ba2698f1SMatthew G. Knepley   Output Parameter:
4934ba2698f1SMatthew G. Knepley . celltypeLabel - The DMLabel recording cell polytope type
4935ba2698f1SMatthew G. Knepley 
4936412e9a14SMatthew G. Knepley   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4937412e9a14SMatthew G. Knepley   DMCreateLabel(dm, "celltype") beforehand.
4938412e9a14SMatthew G. Knepley 
4939ba2698f1SMatthew G. Knepley   Level: developer
4940ba2698f1SMatthew G. Knepley 
4941db781477SPatrick Sanan .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
4942ba2698f1SMatthew G. Knepley @*/
4943ba2698f1SMatthew G. Knepley PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4944ba2698f1SMatthew G. Knepley {
4945ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
4946ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4947ba2698f1SMatthew G. Knepley   PetscValidPointer(celltypeLabel, 2);
49489566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
4949ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
4950ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4951ba2698f1SMatthew G. Knepley }
4952ba2698f1SMatthew G. Knepley 
4953ba2698f1SMatthew G. Knepley /*@
4954ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
4955ba2698f1SMatthew G. Knepley 
4956ba2698f1SMatthew G. Knepley   Not Collective
4957ba2698f1SMatthew G. Knepley 
4958d8d19677SJose E. Roman   Input Parameters:
4959ba2698f1SMatthew G. Knepley + dm   - The DMPlex object
4960ba2698f1SMatthew G. Knepley - cell - The cell
4961ba2698f1SMatthew G. Knepley 
4962ba2698f1SMatthew G. Knepley   Output Parameter:
4963ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
4964ba2698f1SMatthew G. Knepley 
4965ba2698f1SMatthew G. Knepley   Level: intermediate
4966ba2698f1SMatthew G. Knepley 
4967db781477SPatrick Sanan .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
4968ba2698f1SMatthew G. Knepley @*/
4969ba2698f1SMatthew G. Knepley PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4970ba2698f1SMatthew G. Knepley {
4971ba2698f1SMatthew G. Knepley   DMLabel        label;
4972ba2698f1SMatthew G. Knepley   PetscInt       ct;
4973ba2698f1SMatthew G. Knepley 
4974ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
4975ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4976ba2698f1SMatthew G. Knepley   PetscValidPointer(celltype, 3);
49779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
49789566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(label, cell, &ct));
497963a3b9bcSJacob Faibussowitsch   PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
4980ba2698f1SMatthew G. Knepley   *celltype = (DMPolytopeType) ct;
4981ba2698f1SMatthew G. Knepley   PetscFunctionReturn(0);
4982ba2698f1SMatthew G. Knepley }
4983ba2698f1SMatthew G. Knepley 
4984412e9a14SMatthew G. Knepley /*@
4985412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
4986412e9a14SMatthew G. Knepley 
4987412e9a14SMatthew G. Knepley   Not Collective
4988412e9a14SMatthew G. Knepley 
4989412e9a14SMatthew G. Knepley   Input Parameters:
4990412e9a14SMatthew G. Knepley + dm   - The DMPlex object
4991412e9a14SMatthew G. Knepley . cell - The cell
4992412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
4993412e9a14SMatthew G. Knepley 
4994412e9a14SMatthew G. Knepley   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
4995412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
4996412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
4997412e9a14SMatthew G. Knepley   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
4998412e9a14SMatthew G. Knepley 
4999412e9a14SMatthew G. Knepley   Level: advanced
5000412e9a14SMatthew G. Knepley 
5001db781477SPatrick Sanan .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5002412e9a14SMatthew G. Knepley @*/
5003412e9a14SMatthew G. Knepley PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5004412e9a14SMatthew G. Knepley {
5005412e9a14SMatthew G. Knepley   DMLabel        label;
5006412e9a14SMatthew G. Knepley 
5007412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5008412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
50109566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
5011412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
5012412e9a14SMatthew G. Knepley }
5013412e9a14SMatthew G. Knepley 
50140adebc6cSBarry Smith PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
50150adebc6cSBarry Smith {
5016efe440bfSMatthew G. Knepley   PetscSection   section, s;
5017efe440bfSMatthew G. Knepley   Mat            m;
50183e922f36SToby Isaac   PetscInt       maxHeight;
5019552f7358SJed Brown 
5020552f7358SJed Brown   PetscFunctionBegin;
50219566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
50229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
50239566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
50249566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
50259566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
50269566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
50279566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
50289566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
50299566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
50309566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&s));
50319566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&m));
50328f4c458bSMatthew G. Knepley 
50339566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
50349566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5035552f7358SJed Brown   PetscFunctionReturn(0);
5036552f7358SJed Brown }
5037552f7358SJed Brown 
5038f19dbd58SToby Isaac PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5039f19dbd58SToby Isaac {
5040f19dbd58SToby Isaac   Vec            coordsLocal;
5041f19dbd58SToby Isaac   DM             coordsDM;
5042f19dbd58SToby Isaac 
5043f19dbd58SToby Isaac   PetscFunctionBegin;
5044f19dbd58SToby Isaac   *field = NULL;
50459566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal));
50469566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&coordsDM));
5047f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
50489566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5049f19dbd58SToby Isaac   }
5050f19dbd58SToby Isaac   PetscFunctionReturn(0);
5051f19dbd58SToby Isaac }
5052f19dbd58SToby Isaac 
50537cd05799SMatthew G. Knepley /*@C
50547cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
50557cd05799SMatthew G. Knepley 
50567cd05799SMatthew G. Knepley   Not Collective
50577cd05799SMatthew G. Knepley 
50587cd05799SMatthew G. Knepley   Input Parameters:
50597cd05799SMatthew G. Knepley . dm        - The DMPlex object
50607cd05799SMatthew G. Knepley 
50617cd05799SMatthew G. Knepley   Output Parameter:
50627cd05799SMatthew G. Knepley . section - The PetscSection object
50637cd05799SMatthew G. Knepley 
50647cd05799SMatthew G. Knepley   Level: developer
50657cd05799SMatthew G. Knepley 
5066db781477SPatrick Sanan .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`
50677cd05799SMatthew G. Knepley @*/
50680adebc6cSBarry Smith PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
50690adebc6cSBarry Smith {
5070552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
5071552f7358SJed Brown 
5072552f7358SJed Brown   PetscFunctionBegin;
5073552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5074552f7358SJed Brown   if (section) *section = mesh->coneSection;
5075552f7358SJed Brown   PetscFunctionReturn(0);
5076552f7358SJed Brown }
5077552f7358SJed Brown 
50787cd05799SMatthew G. Knepley /*@C
50797cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
50807cd05799SMatthew G. Knepley 
50817cd05799SMatthew G. Knepley   Not Collective
50827cd05799SMatthew G. Knepley 
50837cd05799SMatthew G. Knepley   Input Parameters:
50847cd05799SMatthew G. Knepley . dm        - The DMPlex object
50857cd05799SMatthew G. Knepley 
50867cd05799SMatthew G. Knepley   Output Parameter:
50877cd05799SMatthew G. Knepley . section - The PetscSection object
50887cd05799SMatthew G. Knepley 
50897cd05799SMatthew G. Knepley   Level: developer
50907cd05799SMatthew G. Knepley 
5091db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`
50927cd05799SMatthew G. Knepley @*/
50938cb4d582SMatthew G. Knepley PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
50948cb4d582SMatthew G. Knepley {
50958cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex*) dm->data;
50968cb4d582SMatthew G. Knepley 
50978cb4d582SMatthew G. Knepley   PetscFunctionBegin;
50988cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50998cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
51008cb4d582SMatthew G. Knepley   PetscFunctionReturn(0);
51018cb4d582SMatthew G. Knepley }
51028cb4d582SMatthew G. Knepley 
51037cd05799SMatthew G. Knepley /*@C
51047cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
51057cd05799SMatthew G. Knepley 
51067cd05799SMatthew G. Knepley   Not Collective
51077cd05799SMatthew G. Knepley 
51087cd05799SMatthew G. Knepley   Input Parameters:
51097cd05799SMatthew G. Knepley . dm        - The DMPlex object
51107cd05799SMatthew G. Knepley 
51117cd05799SMatthew G. Knepley   Output Parameter:
51127cd05799SMatthew G. Knepley . cones - The cone for each point
51137cd05799SMatthew G. Knepley 
51147cd05799SMatthew G. Knepley   Level: developer
51157cd05799SMatthew G. Knepley 
5116db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`
51177cd05799SMatthew G. Knepley @*/
5118a6dfd86eSKarl Rupp PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5119a6dfd86eSKarl Rupp {
5120552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
5121552f7358SJed Brown 
5122552f7358SJed Brown   PetscFunctionBegin;
5123552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5124552f7358SJed Brown   if (cones) *cones = mesh->cones;
5125552f7358SJed Brown   PetscFunctionReturn(0);
5126552f7358SJed Brown }
5127552f7358SJed Brown 
51287cd05799SMatthew G. Knepley /*@C
51297cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
51307cd05799SMatthew G. Knepley 
51317cd05799SMatthew G. Knepley   Not Collective
51327cd05799SMatthew G. Knepley 
51337cd05799SMatthew G. Knepley   Input Parameters:
51347cd05799SMatthew G. Knepley . dm        - The DMPlex object
51357cd05799SMatthew G. Knepley 
51367cd05799SMatthew G. Knepley   Output Parameter:
5137b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
51387cd05799SMatthew G. Knepley 
51397cd05799SMatthew G. Knepley   Level: developer
51407cd05799SMatthew G. Knepley 
5141b5a892a1SMatthew G. Knepley   Notes:
5142b5a892a1SMatthew G. Knepley   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5143b5a892a1SMatthew G. Knepley 
5144b5a892a1SMatthew G. Knepley   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5145b5a892a1SMatthew G. Knepley 
5146db781477SPatrick Sanan .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`
51477cd05799SMatthew G. Knepley @*/
5148a6dfd86eSKarl Rupp PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5149a6dfd86eSKarl Rupp {
5150552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
5151552f7358SJed Brown 
5152552f7358SJed Brown   PetscFunctionBegin;
5153552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5154552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5155552f7358SJed Brown   PetscFunctionReturn(0);
5156552f7358SJed Brown }
5157552f7358SJed Brown 
5158552f7358SJed Brown /******************************** FEM Support **********************************/
5159552f7358SJed Brown 
51609e8305c2SJed Brown /*
51619e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
51629e8305c2SJed Brown  representing a line in the section.
51639e8305c2SJed Brown */
51649e8305c2SJed Brown static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
51659e8305c2SJed Brown {
51669e8305c2SJed Brown   PetscFunctionBeginHot;
51679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5168a433471fSStefano Zampini   if (line < 0) {
5169a433471fSStefano Zampini     *k = 0;
5170a433471fSStefano Zampini     *Nc = 0;
5171a433471fSStefano Zampini   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
51729e8305c2SJed Brown     *k = 1;
51739e8305c2SJed Brown   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
51749e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
51759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
51769e8305c2SJed Brown     *k = *k / *Nc + 1;
51779e8305c2SJed Brown   }
51789e8305c2SJed Brown   PetscFunctionReturn(0);
51799e8305c2SJed Brown }
51809e8305c2SJed Brown 
5181a4355906SMatthew Knepley /*@
5182bc1eb3faSJed Brown 
5183bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5184bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
51851bb6d2a8SBarry Smith   section provided (or the section of the DM).
5186a4355906SMatthew Knepley 
5187a4355906SMatthew Knepley   Input Parameters:
5188a4355906SMatthew Knepley + dm      - The DM
5189a4355906SMatthew Knepley . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5190a4355906SMatthew Knepley - section - The PetscSection to reorder, or NULL for the default section
5191a4355906SMatthew Knepley 
5192a4355906SMatthew Knepley   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5193a4355906SMatthew Knepley   degree of the basis.
5194a4355906SMatthew Knepley 
5195bc1eb3faSJed Brown   Example:
5196bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5197bc1eb3faSJed Brown .vb
5198bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5199bc1eb3faSJed Brown 
5200bc1eb3faSJed Brown   v4 -- e6 -- v3
5201bc1eb3faSJed Brown   |           |
5202bc1eb3faSJed Brown   e7    c0    e8
5203bc1eb3faSJed Brown   |           |
5204bc1eb3faSJed Brown   v1 -- e5 -- v2
5205bc1eb3faSJed Brown .ve
5206bc1eb3faSJed Brown 
5207bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5208bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5209bc1eb3faSJed Brown .vb
5210bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5211bc1eb3faSJed Brown     v1 -> [4]
5212bc1eb3faSJed Brown     ...
5213bc1eb3faSJed Brown     e5 -> [8, 9]
5214bc1eb3faSJed Brown .ve
5215bc1eb3faSJed Brown 
5216bc1eb3faSJed Brown   which corresponds to the dofs
5217bc1eb3faSJed Brown .vb
5218bc1eb3faSJed Brown     6   10  11  7
5219bc1eb3faSJed Brown     13  2   3   15
5220bc1eb3faSJed Brown     12  0   1   14
5221bc1eb3faSJed Brown     4   8   9   5
5222bc1eb3faSJed Brown .ve
5223bc1eb3faSJed Brown 
5224bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5225bc1eb3faSJed Brown .vb
5226bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5227bc1eb3faSJed Brown .ve
5228bc1eb3faSJed Brown 
5229bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5230bc1eb3faSJed Brown .vb
5231bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5232bc1eb3faSJed Brown .ve
5233bc1eb3faSJed Brown 
5234a4355906SMatthew Knepley   Level: developer
5235a4355906SMatthew Knepley 
5236db781477SPatrick Sanan .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5237a4355906SMatthew Knepley @*/
5238bc1eb3faSJed Brown PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
52393194fc30SMatthew G. Knepley {
52407391a63aSMatthew G. Knepley   DMLabel        label;
5241bb197d40SJed Brown   PetscInt       dim, depth = -1, eStart = -1, Nf;
52429e8305c2SJed Brown   PetscBool      vertexchart;
52433194fc30SMatthew G. Knepley 
52443194fc30SMatthew G. Knepley   PetscFunctionBegin;
52459566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
5246a433471fSStefano Zampini   if (dim < 1) PetscFunctionReturn(0);
5247a433471fSStefano Zampini   if (point < 0) {
5248a433471fSStefano Zampini     PetscInt sStart,sEnd;
5249a433471fSStefano Zampini 
52509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5251a433471fSStefano Zampini     point = sEnd-sStart ? sStart : point;
5252a433471fSStefano Zampini   }
52539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
52549566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
52559566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
52567391a63aSMatthew G. Knepley   if (depth == 1) {eStart = point;}
52577391a63aSMatthew G. Knepley   else if  (depth == dim) {
52587391a63aSMatthew G. Knepley     const PetscInt *cone;
52597391a63aSMatthew G. Knepley 
52609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5261d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5262d4e6627bSStefano Zampini     else if (dim == 3) {
5263d4e6627bSStefano Zampini       const PetscInt *cone2;
52649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5265d4e6627bSStefano Zampini       eStart = cone2[0];
526663a3b9bcSJacob 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);
526763a3b9bcSJacob 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);
52689e8305c2SJed Brown   {                             /* Determine whether the chart covers all points or just vertices. */
52699e8305c2SJed Brown     PetscInt pStart,pEnd,cStart,cEnd;
52709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd));
52719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section,&cStart,&cEnd));
5272796d0a68SJed Brown     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5273796d0a68SJed Brown     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5274796d0a68SJed Brown     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
52759e8305c2SJed Brown   }
52769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5277bb197d40SJed Brown   for (PetscInt d=1; d<=dim; d++) {
5278bb197d40SJed Brown     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5279bb197d40SJed Brown     PetscInt *perm;
5280bb197d40SJed Brown 
52813194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
52829566063dSJacob Faibussowitsch       PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5283bb197d40SJed Brown       size += PetscPowInt(k+1, d)*Nc;
52843194fc30SMatthew G. Knepley     }
52859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
52863194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5287bb197d40SJed Brown       switch (d) {
5288babf31e0SJed Brown       case 1:
52899566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
5290babf31e0SJed Brown         /*
5291babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5292babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5293babf31e0SJed Brown          */
5294babf31e0SJed Brown         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5295babf31e0SJed Brown         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5296babf31e0SJed Brown         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5297babf31e0SJed Brown         foffset = offset;
5298babf31e0SJed Brown         break;
529989eabcffSMatthew G. Knepley       case 2:
53003194fc30SMatthew 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} */
53019566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
53023194fc30SMatthew G. Knepley         /* The SEM order is
53033194fc30SMatthew G. Knepley 
53043194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
530589eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
53063194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
53073194fc30SMatthew G. Knepley          */
53083194fc30SMatthew G. Knepley         {
53093194fc30SMatthew G. Knepley           const PetscInt of   = 0;
53103194fc30SMatthew G. Knepley           const PetscInt oeb  = of   + PetscSqr(k-1);
53113194fc30SMatthew G. Knepley           const PetscInt oer  = oeb  + (k-1);
53123194fc30SMatthew G. Knepley           const PetscInt oet  = oer  + (k-1);
53133194fc30SMatthew G. Knepley           const PetscInt oel  = oet  + (k-1);
53143194fc30SMatthew G. Knepley           const PetscInt ovlb = oel  + (k-1);
53153194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
53163194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
53173194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
53183194fc30SMatthew G. Knepley           PetscInt       o;
53193194fc30SMatthew G. Knepley 
53203194fc30SMatthew G. Knepley           /* bottom */
53213194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
53223194fc30SMatthew G. Knepley           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
53233194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
53243194fc30SMatthew G. Knepley           /* middle */
53253194fc30SMatthew G. Knepley           for (i = 0; i < k-1; ++i) {
53263194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
53273194fc30SMatthew 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;
53283194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
53293194fc30SMatthew G. Knepley           }
53303194fc30SMatthew G. Knepley           /* top */
53313194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
53323194fc30SMatthew G. Knepley           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
53333194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
53343194fc30SMatthew G. Knepley           foffset = offset;
53353194fc30SMatthew G. Knepley         }
533689eabcffSMatthew G. Knepley         break;
533789eabcffSMatthew G. Knepley       case 3:
533889eabcffSMatthew G. Knepley         /* The original hex closure is
533989eabcffSMatthew G. Knepley 
534089eabcffSMatthew G. Knepley          {c,
534189eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
534289eabcffSMatthew 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,
534389eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
534489eabcffSMatthew G. Knepley          */
53459566063dSJacob Faibussowitsch         PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k));
534689eabcffSMatthew G. Knepley         /* The SEM order is
534789eabcffSMatthew G. Knepley          Bottom Slice
534889eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
534989eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
535089eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
535189eabcffSMatthew G. Knepley 
535289eabcffSMatthew G. Knepley          Middle Slice (j)
535389eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
535489eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
535589eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
535689eabcffSMatthew G. Knepley 
535789eabcffSMatthew G. Knepley          Top Slice
535889eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
535989eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
536089eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
536189eabcffSMatthew G. Knepley          */
536289eabcffSMatthew G. Knepley         {
536389eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
536489eabcffSMatthew G. Knepley           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
536589eabcffSMatthew G. Knepley           const PetscInt oft   = ofb   + PetscSqr(k-1);
536689eabcffSMatthew G. Knepley           const PetscInt off   = oft   + PetscSqr(k-1);
536789eabcffSMatthew G. Knepley           const PetscInt ofk   = off   + PetscSqr(k-1);
536889eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk   + PetscSqr(k-1);
536989eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr   + PetscSqr(k-1);
537089eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl   + PetscSqr(k-1);
537189eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl  + (k-1);
537289eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb  + (k-1);
537389eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr  + (k-1);
537489eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf  + (k-1);
537589eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf  + (k-1);
537689eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr  + (k-1);
537789eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb  + (k-1);
537889eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl  + (k-1);
537989eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf  + (k-1);
538089eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf  + (k-1);
538189eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb  + (k-1);
538289eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb  + (k-1);
538389eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
538489eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
538589eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
538689eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
538789eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
538889eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
538989eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
539089eabcffSMatthew G. Knepley           PetscInt       o, n;
539189eabcffSMatthew G. Knepley 
539289eabcffSMatthew G. Knepley           /* Bottom Slice */
539389eabcffSMatthew G. Knepley           /*   bottom */
539489eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
539589eabcffSMatthew G. Knepley           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
539689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
539789eabcffSMatthew G. Knepley           /*   middle */
539889eabcffSMatthew G. Knepley           for (i = 0; i < k-1; ++i) {
539989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5400316b7f87SMax 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;}
540189eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
54023194fc30SMatthew G. Knepley           }
540389eabcffSMatthew G. Knepley           /*   top */
540489eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
540589eabcffSMatthew G. Knepley           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
540689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
540789eabcffSMatthew G. Knepley 
540889eabcffSMatthew G. Knepley           /* Middle Slice */
540989eabcffSMatthew G. Knepley           for (j = 0; j < k-1; ++j) {
541089eabcffSMatthew G. Knepley             /*   bottom */
541189eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
541289eabcffSMatthew 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;
541389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
541489eabcffSMatthew G. Knepley             /*   middle */
541589eabcffSMatthew G. Knepley             for (i = 0; i < k-1; ++i) {
541689eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
541789eabcffSMatthew 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;
541889eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
541989eabcffSMatthew G. Knepley             }
542089eabcffSMatthew G. Knepley             /*   top */
542189eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
542289eabcffSMatthew 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;
542389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
542489eabcffSMatthew G. Knepley           }
542589eabcffSMatthew G. Knepley 
542689eabcffSMatthew G. Knepley           /* Top Slice */
542789eabcffSMatthew G. Knepley           /*   bottom */
542889eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
542989eabcffSMatthew G. Knepley           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
543089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
543189eabcffSMatthew G. Knepley           /*   middle */
543289eabcffSMatthew G. Knepley           for (i = 0; i < k-1; ++i) {
543389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
543489eabcffSMatthew 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;
543589eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
543689eabcffSMatthew G. Knepley           }
543789eabcffSMatthew G. Knepley           /*   top */
543889eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
543989eabcffSMatthew G. Knepley           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
544089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
544189eabcffSMatthew G. Knepley 
544289eabcffSMatthew G. Knepley           foffset = offset;
544389eabcffSMatthew G. Knepley         }
544489eabcffSMatthew G. Knepley         break;
544563a3b9bcSJacob Faibussowitsch       default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
544689eabcffSMatthew G. Knepley       }
544789eabcffSMatthew G. Knepley     }
544863a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
54493194fc30SMatthew G. Knepley     /* Check permutation */
54503194fc30SMatthew G. Knepley     {
54513194fc30SMatthew G. Knepley       PetscInt *check;
54523194fc30SMatthew G. Knepley 
54539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
54541dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
54551dca8a05SBarry Smith         check[i] = -1;
54561dca8a05SBarry 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]);
54571dca8a05SBarry Smith       }
54583194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
54591dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
54609566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
54613194fc30SMatthew G. Knepley     }
54629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm));
5463a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5464a05c9aa3SJed Brown       PetscInt *loc_perm;
54659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size*2, &loc_perm));
5466a05c9aa3SJed Brown       for (PetscInt i=0; i<size; i++) {
5467a05c9aa3SJed Brown         loc_perm[i] = perm[i];
5468a05c9aa3SJed Brown         loc_perm[size+i] = size + perm[i];
5469a05c9aa3SJed Brown       }
54709566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm));
5471a05c9aa3SJed Brown     }
5472bb197d40SJed Brown   }
54733194fc30SMatthew G. Knepley   PetscFunctionReturn(0);
54743194fc30SMatthew G. Knepley }
54753194fc30SMatthew G. Knepley 
5476e071409bSToby Isaac PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5477e071409bSToby Isaac {
5478e071409bSToby Isaac   PetscDS        prob;
5479e071409bSToby Isaac   PetscInt       depth, Nf, h;
5480e071409bSToby Isaac   DMLabel        label;
5481e071409bSToby Isaac 
5482e071409bSToby Isaac   PetscFunctionBeginHot;
54839566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
5484e071409bSToby Isaac   Nf      = prob->Nf;
5485e071409bSToby Isaac   label   = dm->depthLabel;
5486e071409bSToby Isaac   *dspace = NULL;
5487e071409bSToby Isaac   if (field < Nf) {
5488e071409bSToby Isaac     PetscObject disc = prob->disc[field];
5489e071409bSToby Isaac 
5490e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
5491e071409bSToby Isaac       PetscDualSpace dsp;
5492e071409bSToby Isaac 
54939566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp));
54949566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label,&depth));
54959566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label,point,&h));
5496e071409bSToby Isaac       h    = depth - 1 - h;
5497e071409bSToby Isaac       if (h) {
54989566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace));
5499e071409bSToby Isaac       } else {
5500e071409bSToby Isaac         *dspace = dsp;
5501e071409bSToby Isaac       }
5502e071409bSToby Isaac     }
5503e071409bSToby Isaac   }
5504e071409bSToby Isaac   PetscFunctionReturn(0);
5505e071409bSToby Isaac }
5506e071409bSToby Isaac 
55079fbee547SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5508a6dfd86eSKarl Rupp {
5509552f7358SJed Brown   PetscScalar    *array, *vArray;
5510d9917b9dSMatthew G. Knepley   const PetscInt *cone, *coneO;
55111a271a75SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5512552f7358SJed Brown 
55131b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
55149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
55159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
55169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
55179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
55183f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
55199df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
55209df71ca4SMatthew G. Knepley       PetscInt dof;
5521d9917b9dSMatthew G. Knepley 
55229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
55239df71ca4SMatthew G. Knepley       size += dof;
55249df71ca4SMatthew G. Knepley     }
55259df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
55269df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
55272a3aaacfSMatthew G. Knepley       PetscInt       dof;
55285a1bb5cfSMatthew G. Knepley 
55295a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
55309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
55315a1bb5cfSMatthew G. Knepley       size += dof;
55325a1bb5cfSMatthew G. Knepley     }
55333f7cbbe7SMatthew G. Knepley     if (!values) {
55343f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
55353f7cbbe7SMatthew G. Knepley       PetscFunctionReturn(0);
55363f7cbbe7SMatthew G. Knepley     }
55379566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5538982e9ed1SMatthew G. Knepley   } else {
5539982e9ed1SMatthew G. Knepley     array = *values;
5540982e9ed1SMatthew G. Knepley   }
55419df71ca4SMatthew G. Knepley   size = 0;
55429566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &vArray));
55439df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
55449df71ca4SMatthew G. Knepley     PetscInt     dof, off, d;
55459df71ca4SMatthew G. Knepley     PetscScalar *varr;
5546d9917b9dSMatthew G. Knepley 
55479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
55489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
55499df71ca4SMatthew G. Knepley     varr = &vArray[off];
55501a271a75SMatthew G. Knepley     for (d = 0; d < dof; ++d, ++offset) {
55511a271a75SMatthew G. Knepley       array[offset] = varr[d];
55529df71ca4SMatthew G. Knepley     }
55539df71ca4SMatthew G. Knepley     size += dof;
55549df71ca4SMatthew G. Knepley   }
55559df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
55569df71ca4SMatthew G. Knepley     const PetscInt cp = cone[p];
55579df71ca4SMatthew G. Knepley     PetscInt       o  = coneO[p];
55585a1bb5cfSMatthew G. Knepley     PetscInt       dof, off, d;
55595a1bb5cfSMatthew G. Knepley     PetscScalar   *varr;
55605a1bb5cfSMatthew G. Knepley 
556152ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
55629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
55639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
55645a1bb5cfSMatthew G. Knepley     varr = &vArray[off];
55655a1bb5cfSMatthew G. Knepley     if (o >= 0) {
55661a271a75SMatthew G. Knepley       for (d = 0; d < dof; ++d, ++offset) {
55671a271a75SMatthew G. Knepley         array[offset] = varr[d];
55685a1bb5cfSMatthew G. Knepley       }
55695a1bb5cfSMatthew G. Knepley     } else {
55701a271a75SMatthew G. Knepley       for (d = dof-1; d >= 0; --d, ++offset) {
55711a271a75SMatthew G. Knepley         array[offset] = varr[d];
55725a1bb5cfSMatthew G. Knepley       }
55735a1bb5cfSMatthew G. Knepley     }
55749df71ca4SMatthew G. Knepley     size += dof;
55755a1bb5cfSMatthew G. Knepley   }
55769566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &vArray));
55779df71ca4SMatthew G. Knepley   if (!*values) {
55785a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
55795a1bb5cfSMatthew G. Knepley     *values = array;
55809df71ca4SMatthew G. Knepley   } else {
558163a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
55828c312ff3SMatthew G. Knepley     *csize = size;
55839df71ca4SMatthew G. Knepley   }
55845a1bb5cfSMatthew G. Knepley   PetscFunctionReturn(0);
55855a1bb5cfSMatthew G. Knepley }
5586d9917b9dSMatthew G. Knepley 
558727f02ce8SMatthew G. Knepley /* Compress out points not in the section */
55889fbee547SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
558927f02ce8SMatthew G. Knepley {
559027f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
559127f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
559227f02ce8SMatthew G. Knepley 
55939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
559427f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
559527f02ce8SMatthew G. Knepley     const PetscInt r = points[p*2];
559627f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
559727f02ce8SMatthew G. Knepley       points[q*2]   = r;
559827f02ce8SMatthew G. Knepley       points[q*2+1] = points[p*2+1];
559927f02ce8SMatthew G. Knepley       ++q;
560027f02ce8SMatthew G. Knepley     }
560127f02ce8SMatthew G. Knepley   }
560227f02ce8SMatthew G. Knepley   *numPoints = q;
560327f02ce8SMatthew G. Knepley   return 0;
560427f02ce8SMatthew G. Knepley }
560527f02ce8SMatthew G. Knepley 
560697529cf3SJed Brown /* Compressed closure does not apply closure permutation */
56071dc59d61SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5608923c78e0SToby Isaac {
560927f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
5610923c78e0SToby Isaac   PetscInt       np, *pts = NULL;
5611923c78e0SToby Isaac 
5612923c78e0SToby Isaac   PetscFunctionBeginHot;
56139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints));
561427f02ce8SMatthew G. Knepley   if (*clPoints) {
5615923c78e0SToby Isaac     PetscInt dof, off;
5616923c78e0SToby Isaac 
56179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
56189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
56199566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
5620923c78e0SToby Isaac     np   = dof/2;
5621923c78e0SToby Isaac     pts  = (PetscInt *) &cla[off];
562227f02ce8SMatthew G. Knepley   } else {
56239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts));
56249566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
5625923c78e0SToby Isaac   }
5626923c78e0SToby Isaac   *numPoints = np;
5627923c78e0SToby Isaac   *points    = pts;
5628923c78e0SToby Isaac   *clp       = cla;
5629923c78e0SToby Isaac   PetscFunctionReturn(0);
5630923c78e0SToby Isaac }
5631923c78e0SToby Isaac 
56321dc59d61SMatthew G. Knepley PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5633923c78e0SToby Isaac {
5634923c78e0SToby Isaac   PetscFunctionBeginHot;
5635923c78e0SToby Isaac   if (!*clPoints) {
56369566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5637923c78e0SToby Isaac   } else {
56389566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
5639923c78e0SToby Isaac   }
5640923c78e0SToby Isaac   *numPoints = 0;
5641923c78e0SToby Isaac   *points    = NULL;
5642923c78e0SToby Isaac   *clSec     = NULL;
5643923c78e0SToby Isaac   *clPoints  = NULL;
5644923c78e0SToby Isaac   *clp       = NULL;
5645923c78e0SToby Isaac   PetscFunctionReturn(0);
5646923c78e0SToby Isaac }
5647923c78e0SToby Isaac 
56489fbee547SJacob 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[])
56491a271a75SMatthew G. Knepley {
56501a271a75SMatthew G. Knepley   PetscInt          offset = 0, p;
565197e99dd9SToby Isaac   const PetscInt    **perms = NULL;
565297e99dd9SToby Isaac   const PetscScalar **flips = NULL;
56531a271a75SMatthew G. Knepley 
56541a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5655fe02ba77SJed Brown   *size = 0;
56569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips));
565797e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
565897e99dd9SToby Isaac     const PetscInt    point = points[2*p];
565997e99dd9SToby Isaac     const PetscInt    *perm = perms ? perms[p] : NULL;
566097e99dd9SToby Isaac     const PetscScalar *flip = flips ? flips[p] : NULL;
56611a271a75SMatthew G. Knepley     PetscInt          dof, off, d;
56621a271a75SMatthew G. Knepley     const PetscScalar *varr;
56631a271a75SMatthew G. Knepley 
56649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
56659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
56661a271a75SMatthew G. Knepley     varr = &vArray[off];
566797e99dd9SToby Isaac     if (clperm) {
566897e99dd9SToby Isaac       if (perm) {
566997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
56701a271a75SMatthew G. Knepley       } else {
567197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
567297e99dd9SToby Isaac       }
567397e99dd9SToby Isaac       if (flip) {
567497e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
567597e99dd9SToby Isaac       }
567697e99dd9SToby Isaac     } else {
567797e99dd9SToby Isaac       if (perm) {
567897e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
567997e99dd9SToby Isaac       } else {
568097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
568197e99dd9SToby Isaac       }
568297e99dd9SToby Isaac       if (flip) {
568397e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
56841a271a75SMatthew G. Knepley       }
56851a271a75SMatthew G. Knepley     }
568697e99dd9SToby Isaac     offset += dof;
568797e99dd9SToby Isaac   }
56889566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips));
56891a271a75SMatthew G. Knepley   *size = offset;
56901a271a75SMatthew G. Knepley   PetscFunctionReturn(0);
56911a271a75SMatthew G. Knepley }
56921a271a75SMatthew G. Knepley 
56939fbee547SJacob 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[])
56941a271a75SMatthew G. Knepley {
56951a271a75SMatthew G. Knepley   PetscInt          offset = 0, f;
56961a271a75SMatthew G. Knepley 
56971a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
5698fe02ba77SJed Brown   *size = 0;
56991a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
570097e99dd9SToby Isaac     PetscInt          p;
570197e99dd9SToby Isaac     const PetscInt    **perms = NULL;
570297e99dd9SToby Isaac     const PetscScalar **flips = NULL;
57031a271a75SMatthew G. Knepley 
57049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
570597e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
570697e99dd9SToby Isaac       const PetscInt    point = points[2*p];
570797e99dd9SToby Isaac       PetscInt          fdof, foff, b;
57081a271a75SMatthew G. Knepley       const PetscScalar *varr;
570997e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
571097e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
57111a271a75SMatthew G. Knepley 
57129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
57139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
57141a271a75SMatthew G. Knepley       varr = &vArray[foff];
571597e99dd9SToby Isaac       if (clperm) {
571697e99dd9SToby Isaac         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
571797e99dd9SToby Isaac         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
571897e99dd9SToby Isaac         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
57191a271a75SMatthew G. Knepley       } else {
572097e99dd9SToby Isaac         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
572197e99dd9SToby Isaac         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
572297e99dd9SToby Isaac         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
57231a271a75SMatthew G. Knepley       }
572497e99dd9SToby Isaac       offset += fdof;
57251a271a75SMatthew G. Knepley     }
57269566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
57271a271a75SMatthew G. Knepley   }
57281a271a75SMatthew G. Knepley   *size = offset;
57291a271a75SMatthew G. Knepley   PetscFunctionReturn(0);
57301a271a75SMatthew G. Knepley }
57311a271a75SMatthew G. Knepley 
5732552f7358SJed Brown /*@C
5733552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5734552f7358SJed Brown 
5735552f7358SJed Brown   Not collective
5736552f7358SJed Brown 
5737552f7358SJed Brown   Input Parameters:
5738552f7358SJed Brown + dm - The DM
5739552f7358SJed Brown . section - The section describing the layout in v, or NULL to use the default section
5740552f7358SJed Brown . v - The local vector
57416b867d5aSJose E. Roman - point - The point in the DM
5742552f7358SJed Brown 
57436b867d5aSJose E. Roman   Input/Output Parameters:
57446b867d5aSJose E. Roman + csize  - The size of the input values array, or NULL; on output the number of values in the closure
57456b867d5aSJose E. Roman - values - An array to use for the values, or NULL to have it allocated automatically;
57466b867d5aSJose E. Roman            if the user provided NULL, it is a borrowed array and should not be freed
574722c1ee49SMatthew G. Knepley 
574822c1ee49SMatthew G. Knepley $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
574922c1ee49SMatthew G. Knepley $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
575022c1ee49SMatthew G. Knepley $ assembly function, and a user may already have allocated storage for this operation.
575122c1ee49SMatthew G. Knepley $
575222c1ee49SMatthew G. Knepley $ A typical use could be
575322c1ee49SMatthew G. Knepley $
575422c1ee49SMatthew G. Knepley $  values = NULL;
57559566063dSJacob Faibussowitsch $  PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
575622c1ee49SMatthew G. Knepley $  for (cl = 0; cl < clSize; ++cl) {
575722c1ee49SMatthew G. Knepley $    <Compute on closure>
575822c1ee49SMatthew G. Knepley $  }
57599566063dSJacob Faibussowitsch $  PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
576022c1ee49SMatthew G. Knepley $
576122c1ee49SMatthew G. Knepley $ or
576222c1ee49SMatthew G. Knepley $
576322c1ee49SMatthew G. Knepley $  PetscMalloc1(clMaxSize, &values);
576422c1ee49SMatthew G. Knepley $  for (p = pStart; p < pEnd; ++p) {
576522c1ee49SMatthew G. Knepley $    clSize = clMaxSize;
57669566063dSJacob Faibussowitsch $    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
576722c1ee49SMatthew G. Knepley $    for (cl = 0; cl < clSize; ++cl) {
576822c1ee49SMatthew G. Knepley $      <Compute on closure>
576922c1ee49SMatthew G. Knepley $    }
577022c1ee49SMatthew G. Knepley $  }
577122c1ee49SMatthew G. Knepley $  PetscFree(values);
5772552f7358SJed Brown 
5773552f7358SJed Brown   Fortran Notes:
5774552f7358SJed Brown   Since it returns an array, this routine is only available in Fortran 90, and you must
5775552f7358SJed Brown   include petsc.h90 in your code.
5776552f7358SJed Brown 
5777552f7358SJed Brown   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5778552f7358SJed Brown 
5779552f7358SJed Brown   Level: intermediate
5780552f7358SJed Brown 
5781db781477SPatrick Sanan .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
5782552f7358SJed Brown @*/
5783552f7358SJed Brown PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5784552f7358SJed Brown {
5785552f7358SJed Brown   PetscSection       clSection;
5786d9917b9dSMatthew G. Knepley   IS                 clPoints;
5787552f7358SJed Brown   PetscInt          *points = NULL;
5788c459fbc1SJed Brown   const PetscInt    *clp, *perm;
5789c459fbc1SJed Brown   PetscInt           depth, numFields, numPoints, asize;
5790552f7358SJed Brown 
5791d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
5792552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
57939566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
57941a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
57951a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
57969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
57979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
5798552f7358SJed Brown   if (depth == 1 && numFields < 2) {
57999566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
5800552f7358SJed Brown     PetscFunctionReturn(0);
5801552f7358SJed Brown   }
58021a271a75SMatthew G. Knepley   /* Get points */
58039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5804c459fbc1SJed Brown   /* Get sizes */
5805c459fbc1SJed Brown   asize = 0;
5806c459fbc1SJed Brown   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5807c459fbc1SJed Brown     PetscInt dof;
58089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
58091a271a75SMatthew G. Knepley     asize += dof;
5810552f7358SJed Brown   }
5811c459fbc1SJed Brown   if (values) {
5812c459fbc1SJed Brown     const PetscScalar *vArray;
5813c459fbc1SJed Brown     PetscInt          size;
5814c459fbc1SJed Brown 
5815c459fbc1SJed Brown     if (*values) {
581663a3b9bcSJacob 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);
58179566063dSJacob Faibussowitsch     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
58189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm));
58199566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(v, &vArray));
58201a271a75SMatthew G. Knepley     /* Get values */
58219566063dSJacob Faibussowitsch     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
58229566063dSJacob Faibussowitsch     else               PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
582363a3b9bcSJacob Faibussowitsch     PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
58241a271a75SMatthew G. Knepley     /* Cleanup array */
58259566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(v, &vArray));
5826d0f6b257SMatthew G. Knepley   }
5827c459fbc1SJed Brown   if (csize) *csize = asize;
5828c459fbc1SJed Brown   /* Cleanup points */
58299566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5830552f7358SJed Brown   PetscFunctionReturn(0);
5831552f7358SJed Brown }
5832552f7358SJed Brown 
5833e5c487bfSMatthew G. Knepley PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5834e5c487bfSMatthew G. Knepley {
5835e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
5836e5c487bfSMatthew G. Knepley   PetscSection       clSection;
5837e5c487bfSMatthew G. Knepley   IS                 clPoints;
5838e5c487bfSMatthew G. Knepley   PetscScalar       *array;
5839e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
5840e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
5841c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
5842c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5843e5c487bfSMatthew G. Knepley 
5844e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
5845e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58469566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
5847e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5848e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
58499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
58509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
58519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
5852e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
58539566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
5854e5c487bfSMatthew G. Knepley     PetscFunctionReturn(0);
5855e5c487bfSMatthew G. Knepley   }
5856e5c487bfSMatthew G. Knepley   /* Get points */
58579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5858c459fbc1SJed Brown   for (clsize=0,p=0; p<Np; p++) {
5859c459fbc1SJed Brown     PetscInt dof;
58609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2*p], &dof));
5861c459fbc1SJed Brown     clsize += dof;
5862c459fbc1SJed Brown   }
58639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm));
5864e5c487bfSMatthew G. Knepley   /* Filter points */
5865e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints*2; p += 2) {
5866e5c487bfSMatthew G. Knepley     PetscInt dep;
5867e5c487bfSMatthew G. Knepley 
58689566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
5869e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
5870e5c487bfSMatthew G. Knepley     points[Np*2+0] = points[p];
5871e5c487bfSMatthew G. Knepley     points[Np*2+1] = points[p+1];
5872e5c487bfSMatthew G. Knepley     ++Np;
5873e5c487bfSMatthew G. Knepley   }
5874e5c487bfSMatthew G. Knepley   /* Get array */
5875e5c487bfSMatthew G. Knepley   if (!values || !*values) {
5876e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
5877e5c487bfSMatthew G. Knepley 
5878e5c487bfSMatthew G. Knepley     for (p = 0; p < Np*2; p += 2) {
58799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
5880e5c487bfSMatthew G. Knepley       asize += dof;
5881e5c487bfSMatthew G. Knepley     }
5882e5c487bfSMatthew G. Knepley     if (!values) {
58839566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5884e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
5885e5c487bfSMatthew G. Knepley       PetscFunctionReturn(0);
5886e5c487bfSMatthew G. Knepley     }
58879566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
5888e5c487bfSMatthew G. Knepley   } else {
5889e5c487bfSMatthew G. Knepley     array = *values;
5890e5c487bfSMatthew G. Knepley   }
58919566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
5892e5c487bfSMatthew G. Knepley   /* Get values */
58939566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
58949566063dSJacob Faibussowitsch   else               PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
5895e5c487bfSMatthew G. Knepley   /* Cleanup points */
58969566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
5897e5c487bfSMatthew G. Knepley   /* Cleanup array */
58989566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
5899e5c487bfSMatthew G. Knepley   if (!*values) {
5900e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
5901e5c487bfSMatthew G. Knepley     *values = array;
5902e5c487bfSMatthew G. Knepley   } else {
590363a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
5904e5c487bfSMatthew G. Knepley     *csize = size;
5905e5c487bfSMatthew G. Knepley   }
5906e5c487bfSMatthew G. Knepley   PetscFunctionReturn(0);
5907e5c487bfSMatthew G. Knepley }
5908e5c487bfSMatthew G. Knepley 
5909552f7358SJed Brown /*@C
5910552f7358SJed Brown   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5911552f7358SJed Brown 
5912552f7358SJed Brown   Not collective
5913552f7358SJed Brown 
5914552f7358SJed Brown   Input Parameters:
5915552f7358SJed Brown + dm - The DM
59160298fd71SBarry Smith . section - The section describing the layout in v, or NULL to use the default section
5917552f7358SJed Brown . v - The local vector
5918eaf898f9SPatrick Sanan . point - The point in the DM
59190298fd71SBarry Smith . csize - The number of values in the closure, or NULL
5920552f7358SJed Brown - values - The array of values, which is a borrowed array and should not be freed
5921552f7358SJed Brown 
592222c1ee49SMatthew 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()
592322c1ee49SMatthew G. Knepley 
59243813dfbdSMatthew G Knepley   Fortran Notes:
59253813dfbdSMatthew G Knepley   Since it returns an array, this routine is only available in Fortran 90, and you must
59263813dfbdSMatthew G Knepley   include petsc.h90 in your code.
59273813dfbdSMatthew G Knepley 
59283813dfbdSMatthew G Knepley   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
59293813dfbdSMatthew G Knepley 
5930552f7358SJed Brown   Level: intermediate
5931552f7358SJed Brown 
5932db781477SPatrick Sanan .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
5933552f7358SJed Brown @*/
59347c1f9639SMatthew G Knepley PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5935a6dfd86eSKarl Rupp {
5936552f7358SJed Brown   PetscInt       size = 0;
5937552f7358SJed Brown 
5938552f7358SJed Brown   PetscFunctionBegin;
5939552f7358SJed Brown   /* Should work without recalculating size */
59409566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values));
5941c9fdaa05SMatthew G. Knepley   *values = NULL;
5942552f7358SJed Brown   PetscFunctionReturn(0);
5943552f7358SJed Brown }
5944552f7358SJed Brown 
59459fbee547SJacob Faibussowitsch static inline void add   (PetscScalar *x, PetscScalar y) {*x += y;}
59469fbee547SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5947552f7358SJed Brown 
59489fbee547SJacob 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[])
5949552f7358SJed Brown {
5950552f7358SJed Brown   PetscInt        cdof;   /* The number of constraints on this point */
5951552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5952552f7358SJed Brown   PetscScalar    *a;
5953552f7358SJed Brown   PetscInt        off, cind = 0, k;
5954552f7358SJed Brown 
5955552f7358SJed Brown   PetscFunctionBegin;
59569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
59579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
5958552f7358SJed Brown   a    = &array[off];
5959552f7358SJed Brown   if (!cdof || setBC) {
596097e99dd9SToby Isaac     if (clperm) {
596197e99dd9SToby Isaac       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
596297e99dd9SToby Isaac       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5963552f7358SJed Brown     } else {
596497e99dd9SToby Isaac       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
596597e99dd9SToby Isaac       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5966552f7358SJed Brown     }
5967552f7358SJed Brown   } else {
59689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
596997e99dd9SToby Isaac     if (clperm) {
597097e99dd9SToby Isaac       if (perm) {for (k = 0; k < dof; ++k) {
5971552f7358SJed Brown           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
597297e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5973552f7358SJed Brown         }
5974552f7358SJed Brown       } else {
5975552f7358SJed Brown         for (k = 0; k < dof; ++k) {
5976552f7358SJed Brown           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
597797e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
597897e99dd9SToby Isaac         }
597997e99dd9SToby Isaac       }
598097e99dd9SToby Isaac     } else {
598197e99dd9SToby Isaac       if (perm) {
598297e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
598397e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
598497e99dd9SToby Isaac           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
598597e99dd9SToby Isaac         }
598697e99dd9SToby Isaac       } else {
598797e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
598897e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
598997e99dd9SToby Isaac           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
599097e99dd9SToby Isaac         }
5991552f7358SJed Brown       }
5992552f7358SJed Brown     }
5993552f7358SJed Brown   }
5994552f7358SJed Brown   PetscFunctionReturn(0);
5995552f7358SJed Brown }
5996552f7358SJed Brown 
59979fbee547SJacob 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[])
5998a5e93ea8SMatthew G. Knepley {
5999a5e93ea8SMatthew G. Knepley   PetscInt        cdof;   /* The number of constraints on this point */
6000a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6001a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6002a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6003a5e93ea8SMatthew G. Knepley 
6004a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
60059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
60069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6007a5e93ea8SMatthew G. Knepley   a    = &array[off];
6008a5e93ea8SMatthew G. Knepley   if (cdof) {
60099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
601097e99dd9SToby Isaac     if (clperm) {
601197e99dd9SToby Isaac       if (perm) {
6012a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6013a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
601497e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
601597e99dd9SToby Isaac             cind++;
6016a5e93ea8SMatthew G. Knepley           }
6017a5e93ea8SMatthew G. Knepley         }
6018a5e93ea8SMatthew G. Knepley       } else {
6019a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6020a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
602197e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
602297e99dd9SToby Isaac             cind++;
602397e99dd9SToby Isaac           }
602497e99dd9SToby Isaac         }
602597e99dd9SToby Isaac       }
602697e99dd9SToby Isaac     } else {
602797e99dd9SToby Isaac       if (perm) {
602897e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
602997e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
603097e99dd9SToby Isaac             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
603197e99dd9SToby Isaac             cind++;
603297e99dd9SToby Isaac           }
603397e99dd9SToby Isaac         }
603497e99dd9SToby Isaac       } else {
603597e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
603697e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
603797e99dd9SToby Isaac             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
603897e99dd9SToby Isaac             cind++;
603997e99dd9SToby Isaac           }
6040a5e93ea8SMatthew G. Knepley         }
6041a5e93ea8SMatthew G. Knepley       }
6042a5e93ea8SMatthew G. Knepley     }
6043a5e93ea8SMatthew G. Knepley   }
6044a5e93ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6045a5e93ea8SMatthew G. Knepley }
6046a5e93ea8SMatthew G. Knepley 
60479fbee547SJacob 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[])
6048a6dfd86eSKarl Rupp {
6049552f7358SJed Brown   PetscScalar    *a;
60501a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
60511a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
605297e99dd9SToby Isaac   PetscInt        cind = 0, b;
6053552f7358SJed Brown 
6054552f7358SJed Brown   PetscFunctionBegin;
60559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
60569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
60579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
60581a271a75SMatthew G. Knepley   a    = &array[foff];
6059552f7358SJed Brown   if (!fcdof || setBC) {
606097e99dd9SToby Isaac     if (clperm) {
606197e99dd9SToby Isaac       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
606297e99dd9SToby Isaac       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
6063552f7358SJed Brown     } else {
606497e99dd9SToby Isaac       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
606597e99dd9SToby Isaac       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
6066552f7358SJed Brown     }
6067552f7358SJed Brown   } else {
60689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
606997e99dd9SToby Isaac     if (clperm) {
607097e99dd9SToby Isaac       if (perm) {
607197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
607297e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
607397e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6074552f7358SJed Brown         }
6075552f7358SJed Brown       } else {
607697e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
607797e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
607897e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
607997e99dd9SToby Isaac         }
608097e99dd9SToby Isaac       }
608197e99dd9SToby Isaac     } else {
608297e99dd9SToby Isaac       if (perm) {
608397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
608497e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
608597e99dd9SToby Isaac           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
608697e99dd9SToby Isaac         }
608797e99dd9SToby Isaac       } else {
608897e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
608997e99dd9SToby Isaac           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
609097e99dd9SToby Isaac           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6091552f7358SJed Brown         }
6092552f7358SJed Brown       }
6093552f7358SJed Brown     }
6094552f7358SJed Brown   }
60951a271a75SMatthew G. Knepley   *offset += fdof;
6096552f7358SJed Brown   PetscFunctionReturn(0);
6097552f7358SJed Brown }
6098552f7358SJed Brown 
60999fbee547SJacob 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[])
6100a5e93ea8SMatthew G. Knepley {
6101a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
61021a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
61031a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
61045da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6105ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6106a5e93ea8SMatthew G. Knepley 
6107a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
61089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
61099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
61109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
61119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
61121a271a75SMatthew G. Knepley   a    = &array[foff];
6113a5e93ea8SMatthew G. Knepley   if (fcdof) {
6114ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
61159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
611697e99dd9SToby Isaac     if (clperm) {
611797e99dd9SToby Isaac       if (perm) {
6118ba322698SMatthew G. Knepley         if (comps) {
6119ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6120ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61215da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6122ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6123ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6124ba322698SMatthew G. Knepley           }
6125ba322698SMatthew G. Knepley         } else {
612697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
612797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
612897e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6129a5e93ea8SMatthew G. Knepley               ++cind;
6130a5e93ea8SMatthew G. Knepley             }
6131a5e93ea8SMatthew G. Knepley           }
6132ba322698SMatthew G. Knepley         }
6133ba322698SMatthew G. Knepley       } else {
6134ba322698SMatthew G. Knepley         if (comps) {
6135ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6136ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61375da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6138ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6139ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6140ba322698SMatthew G. Knepley           }
6141a5e93ea8SMatthew G. Knepley         } else {
614297e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
614397e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
614497e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
614597e99dd9SToby Isaac               ++cind;
614697e99dd9SToby Isaac             }
614797e99dd9SToby Isaac           }
614897e99dd9SToby Isaac         }
6149ba322698SMatthew G. Knepley       }
615097e99dd9SToby Isaac     } else {
615197e99dd9SToby Isaac       if (perm) {
6152ba322698SMatthew G. Knepley         if (comps) {
6153ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6154ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61555da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6156ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6157ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6158ba322698SMatthew G. Knepley           }
6159ba322698SMatthew G. Knepley         } else {
616097e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
616197e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
616297e99dd9SToby Isaac               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
616397e99dd9SToby Isaac               ++cind;
616497e99dd9SToby Isaac             }
616597e99dd9SToby Isaac           }
6166ba322698SMatthew G. Knepley         }
6167ba322698SMatthew G. Knepley       } else {
6168ba322698SMatthew G. Knepley         if (comps) {
6169ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6170ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
61715da9d227SMatthew G. Knepley             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6172ba322698SMatthew G. Knepley             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6173ba322698SMatthew G. Knepley             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6174ba322698SMatthew G. Knepley           }
617597e99dd9SToby Isaac         } else {
617697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
617797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
617897e99dd9SToby Isaac               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6179a5e93ea8SMatthew G. Knepley               ++cind;
6180a5e93ea8SMatthew G. Knepley             }
6181a5e93ea8SMatthew G. Knepley           }
6182a5e93ea8SMatthew G. Knepley         }
6183a5e93ea8SMatthew G. Knepley       }
6184a5e93ea8SMatthew G. Knepley     }
6185ba322698SMatthew G. Knepley   }
61861a271a75SMatthew G. Knepley   *offset += fdof;
6187a5e93ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6188a5e93ea8SMatthew G. Knepley }
6189a5e93ea8SMatthew G. Knepley 
61909fbee547SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6191a6dfd86eSKarl Rupp {
6192552f7358SJed Brown   PetscScalar    *array;
61931b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
61941b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6195552f7358SJed Brown 
61961b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
61979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
61989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
61999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
62009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
62019566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6202b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6203b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p-1];
6204b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0     : coneO[p-1];
6205b6ebb6e6SMatthew G. Knepley 
6206b6ebb6e6SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
62079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
6208b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
6209b6ebb6e6SMatthew G. Knepley     {
6210b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6211b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
6212b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
6213b6ebb6e6SMatthew G. Knepley 
62149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
62159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6216b6ebb6e6SMatthew G. Knepley       a    = &array[coff];
6217b6ebb6e6SMatthew G. Knepley       if (!cdof) {
6218b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6219b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6220b6ebb6e6SMatthew G. Knepley             a[k] += values[off+k];
6221b6ebb6e6SMatthew G. Knepley           }
6222b6ebb6e6SMatthew G. Knepley         } else {
6223b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6224b6ebb6e6SMatthew G. Knepley             a[k] += values[off+dof-k-1];
6225b6ebb6e6SMatthew G. Knepley           }
6226b6ebb6e6SMatthew G. Knepley         }
6227b6ebb6e6SMatthew G. Knepley       } else {
62289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6229b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6230b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6231b6ebb6e6SMatthew G. Knepley             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6232b6ebb6e6SMatthew G. Knepley             a[k] += values[off+k];
6233b6ebb6e6SMatthew G. Knepley           }
6234b6ebb6e6SMatthew G. Knepley         } else {
6235b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
6236b6ebb6e6SMatthew G. Knepley             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6237b6ebb6e6SMatthew G. Knepley             a[k] += values[off+dof-k-1];
6238b6ebb6e6SMatthew G. Knepley           }
6239b6ebb6e6SMatthew G. Knepley         }
6240b6ebb6e6SMatthew G. Knepley       }
6241b6ebb6e6SMatthew G. Knepley     }
6242b6ebb6e6SMatthew G. Knepley   }
62439566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6244b6ebb6e6SMatthew G. Knepley   PetscFunctionReturn(0);
6245b6ebb6e6SMatthew G. Knepley }
62461b406b76SMatthew G. Knepley 
62471b406b76SMatthew G. Knepley /*@C
62481b406b76SMatthew G. Knepley   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
62491b406b76SMatthew G. Knepley 
62501b406b76SMatthew G. Knepley   Not collective
62511b406b76SMatthew G. Knepley 
62521b406b76SMatthew G. Knepley   Input Parameters:
62531b406b76SMatthew G. Knepley + dm - The DM
62541b406b76SMatthew G. Knepley . section - The section describing the layout in v, or NULL to use the default section
62551b406b76SMatthew G. Knepley . v - The local vector
6256eaf898f9SPatrick Sanan . point - The point in the DM
62571b406b76SMatthew G. Knepley . values - The array of values
625822c1ee49SMatthew 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,
625922c1ee49SMatthew G. Knepley          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
62601b406b76SMatthew G. Knepley 
62611b406b76SMatthew G. Knepley   Fortran Notes:
62621b406b76SMatthew G. Knepley   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
62631b406b76SMatthew G. Knepley 
62641b406b76SMatthew G. Knepley   Level: intermediate
62651b406b76SMatthew G. Knepley 
6266db781477SPatrick Sanan .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
62671b406b76SMatthew G. Knepley @*/
62681b406b76SMatthew G. Knepley PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
62691b406b76SMatthew G. Knepley {
62701b406b76SMatthew G. Knepley   PetscSection    clSection;
62711b406b76SMatthew G. Knepley   IS              clPoints;
62721b406b76SMatthew G. Knepley   PetscScalar    *array;
62731b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
627427f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
6275c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
62761b406b76SMatthew G. Knepley 
62771a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
62781b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
62799566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
62801a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
62811a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
62829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
62839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
62841b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
62859566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
62861b406b76SMatthew G. Knepley     PetscFunctionReturn(0);
62871b406b76SMatthew G. Knepley   }
62881a271a75SMatthew G. Knepley   /* Get points */
62899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6290c459fbc1SJed Brown   for (clsize=0,p=0; p<numPoints; p++) {
6291c459fbc1SJed Brown     PetscInt dof;
62929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2*p], &dof));
6293c459fbc1SJed Brown     clsize += dof;
6294c459fbc1SJed Brown   }
62959566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm));
62961a271a75SMatthew G. Knepley   /* Get array */
62979566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
62981a271a75SMatthew G. Knepley   /* Get values */
6299ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
630097e99dd9SToby Isaac     PetscInt offset = 0, f;
6301552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
630297e99dd9SToby Isaac       const PetscInt    **perms = NULL;
630397e99dd9SToby Isaac       const PetscScalar **flips = NULL;
630497e99dd9SToby Isaac 
63059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6306552f7358SJed Brown       switch (mode) {
6307552f7358SJed Brown       case INSERT_VALUES:
630897e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
630997e99dd9SToby Isaac           const PetscInt    point = points[2*p];
631097e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
631197e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
631297e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6313552f7358SJed Brown         } break;
6314552f7358SJed Brown       case INSERT_ALL_VALUES:
631597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
631697e99dd9SToby Isaac           const PetscInt    point = points[2*p];
631797e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
631897e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
631997e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6320552f7358SJed Brown         } break;
6321a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
632297e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
632397e99dd9SToby Isaac           const PetscInt    point = points[2*p];
632497e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
632597e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
6326ba322698SMatthew G. Knepley           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6327a5e93ea8SMatthew G. Knepley         } break;
6328552f7358SJed Brown       case ADD_VALUES:
632997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
633097e99dd9SToby Isaac           const PetscInt    point = points[2*p];
633197e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
633297e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
633397e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6334552f7358SJed Brown         } break;
6335552f7358SJed Brown       case ADD_ALL_VALUES:
633697e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
633797e99dd9SToby Isaac           const PetscInt    point = points[2*p];
633897e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
633997e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
634097e99dd9SToby Isaac           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6341552f7358SJed Brown         } break;
6342304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
634397e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
634497e99dd9SToby Isaac           const PetscInt    point = points[2*p];
634597e99dd9SToby Isaac           const PetscInt    *perm = perms ? perms[p] : NULL;
634697e99dd9SToby Isaac           const PetscScalar *flip = flips ? flips[p] : NULL;
6347ba322698SMatthew G. Knepley           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6348304ab55fSMatthew G. Knepley         } break;
6349552f7358SJed Brown       default:
635098921bdaSJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6351552f7358SJed Brown       }
63529566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
63531a271a75SMatthew G. Knepley     }
6354552f7358SJed Brown   } else {
63551a271a75SMatthew G. Knepley     PetscInt dof, off;
635697e99dd9SToby Isaac     const PetscInt    **perms = NULL;
635797e99dd9SToby Isaac     const PetscScalar **flips = NULL;
63581a271a75SMatthew G. Knepley 
63599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips));
6360552f7358SJed Brown     switch (mode) {
6361552f7358SJed Brown     case INSERT_VALUES:
636297e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
636397e99dd9SToby Isaac         const PetscInt    point = points[2*p];
636497e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
636597e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
636797e99dd9SToby Isaac         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6368552f7358SJed Brown       } break;
6369552f7358SJed Brown     case INSERT_ALL_VALUES:
637097e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
637197e99dd9SToby Isaac         const PetscInt    point = points[2*p];
637297e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
637397e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
637597e99dd9SToby Isaac         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6376552f7358SJed Brown       } break;
6377a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
637897e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
637997e99dd9SToby Isaac         const PetscInt    point = points[2*p];
638097e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
638197e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
638397e99dd9SToby Isaac         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6384a5e93ea8SMatthew G. Knepley       } break;
6385552f7358SJed Brown     case ADD_VALUES:
638697e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
638797e99dd9SToby Isaac         const PetscInt    point = points[2*p];
638897e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
638997e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
639197e99dd9SToby Isaac         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6392552f7358SJed Brown       } break;
6393552f7358SJed Brown     case ADD_ALL_VALUES:
639497e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
639597e99dd9SToby Isaac         const PetscInt    point = points[2*p];
639697e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
639797e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
63989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
639997e99dd9SToby Isaac         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6400552f7358SJed Brown       } break;
6401304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
640297e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
640397e99dd9SToby Isaac         const PetscInt    point = points[2*p];
640497e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
640597e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
640797e99dd9SToby Isaac         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6408304ab55fSMatthew G. Knepley       } break;
6409552f7358SJed Brown     default:
641098921bdaSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6411552f7358SJed Brown     }
64129566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips));
6413552f7358SJed Brown   }
64141a271a75SMatthew G. Knepley   /* Cleanup points */
64159566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
64161a271a75SMatthew G. Knepley   /* Cleanup array */
64179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6418552f7358SJed Brown   PetscFunctionReturn(0);
6419552f7358SJed Brown }
6420552f7358SJed Brown 
64215f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
64229fbee547SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
64235f790a90SMatthew G. Knepley {
64245f790a90SMatthew G. Knepley   PetscFunctionBegin;
64255f790a90SMatthew G. Knepley   if (label) {
64265f790a90SMatthew G. Knepley     PetscInt       val, fdof;
64275f790a90SMatthew G. Knepley 
64285f790a90SMatthew G. Knepley     /* There is a problem with this:
64295f790a90SMatthew G. Knepley          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
64305f790a90SMatthew G. Knepley        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
64315f790a90SMatthew G. Knepley        Thus I am only going to check val != -1, not val != labelId
64325f790a90SMatthew G. Knepley     */
64339566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, point, &val));
64345f790a90SMatthew G. Knepley     if (val < 0) {
64359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
64365f790a90SMatthew G. Knepley       *offset += fdof;
64375f790a90SMatthew G. Knepley       PetscFunctionReturn(1);
64385f790a90SMatthew G. Knepley     }
64395f790a90SMatthew G. Knepley   }
64405f790a90SMatthew G. Knepley   PetscFunctionReturn(0);
64415f790a90SMatthew G. Knepley }
64425f790a90SMatthew G. Knepley 
644397529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
64445f790a90SMatthew 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)
6445e07394fbSMatthew G. Knepley {
6446e07394fbSMatthew G. Knepley   PetscSection    clSection;
6447e07394fbSMatthew G. Knepley   IS              clPoints;
6448e07394fbSMatthew G. Knepley   PetscScalar    *array;
6449e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
645097529cf3SJed Brown   const PetscInt *clp;
6451e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
645297e99dd9SToby Isaac   PetscInt        offset = 0, f;
6453e07394fbSMatthew G. Knepley 
6454e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
6455e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
64569566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6457e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6458e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
64599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6460e07394fbSMatthew G. Knepley   /* Get points */
64619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6462e07394fbSMatthew G. Knepley   /* Get array */
64639566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6464e07394fbSMatthew G. Knepley   /* Get values */
6465e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
646697e99dd9SToby Isaac     const PetscInt    **perms = NULL;
646797e99dd9SToby Isaac     const PetscScalar **flips = NULL;
646897e99dd9SToby Isaac 
6469e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
6470e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints*2; p += 2) {
6471e07394fbSMatthew G. Knepley         PetscInt fdof;
64729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6473e07394fbSMatthew G. Knepley         offset += fdof;
6474e07394fbSMatthew G. Knepley       }
6475e07394fbSMatthew G. Knepley       continue;
6476e07394fbSMatthew G. Knepley     }
64779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6478e07394fbSMatthew G. Knepley     switch (mode) {
6479e07394fbSMatthew G. Knepley     case INSERT_VALUES:
648097e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
648197e99dd9SToby Isaac         const PetscInt    point = points[2*p];
648297e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
648397e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64845f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
64859566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
6486e07394fbSMatthew G. Knepley       } break;
6487e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
648897e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
648997e99dd9SToby Isaac         const PetscInt    point = points[2*p];
649097e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
649197e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
64925f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
64939566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
6494e07394fbSMatthew G. Knepley       } break;
6495e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
649697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
649797e99dd9SToby Isaac         const PetscInt    point = points[2*p];
649897e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
649997e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65005f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65019566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
6502e07394fbSMatthew G. Knepley       } break;
6503e07394fbSMatthew G. Knepley     case ADD_VALUES:
650497e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
650597e99dd9SToby Isaac         const PetscInt    point = points[2*p];
650697e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
650797e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65085f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65099566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
6510e07394fbSMatthew G. Knepley       } break;
6511e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
651297e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
651397e99dd9SToby Isaac         const PetscInt    point = points[2*p];
651497e99dd9SToby Isaac         const PetscInt    *perm = perms ? perms[p] : NULL;
651597e99dd9SToby Isaac         const PetscScalar *flip = flips ? flips[p] : NULL;
65165f80ce2aSJacob Faibussowitsch         if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue;
65179566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
6518e07394fbSMatthew G. Knepley       } break;
6519e07394fbSMatthew G. Knepley     default:
652098921bdaSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6521e07394fbSMatthew G. Knepley     }
65229566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips));
6523e07394fbSMatthew G. Knepley   }
6524e07394fbSMatthew G. Knepley   /* Cleanup points */
65259566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp));
6526e07394fbSMatthew G. Knepley   /* Cleanup array */
65279566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
6528e07394fbSMatthew G. Knepley   PetscFunctionReturn(0);
6529e07394fbSMatthew G. Knepley }
6530e07394fbSMatthew G. Knepley 
65317cd05799SMatthew G. Knepley static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6532552f7358SJed Brown {
6533552f7358SJed Brown   PetscMPIInt    rank;
6534552f7358SJed Brown   PetscInt       i, j;
6535552f7358SJed Brown 
6536552f7358SJed Brown   PetscFunctionBegin;
65379566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
653863a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
653963a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
654063a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
6541b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
6542557cf195SMatthew G. Knepley   if (!values) PetscFunctionReturn(0);
6543b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
65449566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6545b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
6546519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
65479566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j])));
6548552f7358SJed Brown #else
65499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]));
6550552f7358SJed Brown #endif
6551552f7358SJed Brown     }
65529566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
6553552f7358SJed Brown   }
6554552f7358SJed Brown   PetscFunctionReturn(0);
6555552f7358SJed Brown }
6556552f7358SJed Brown 
655705586334SMatthew G. Knepley /*
655805586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
655905586334SMatthew G. Knepley 
656005586334SMatthew G. Knepley   Input Parameters:
656105586334SMatthew G. Knepley + section - The section for this data layout
656236fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
656305586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
656405586334SMatthew G. Knepley . off     - The global offset of this point
656505586334SMatthew G. Knepley . loff    - The local offset of each field
6566a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
656705586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
656805586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
656905586334SMatthew G. Knepley 
657005586334SMatthew G. Knepley   Output Parameter:
657105586334SMatthew G. Knepley . indices - Indices for dofs on this point
657205586334SMatthew G. Knepley 
657305586334SMatthew G. Knepley   Level: developer
657405586334SMatthew G. Knepley 
657505586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
657605586334SMatthew G. Knepley */
657736fa2b79SJed Brown PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6578a6dfd86eSKarl Rupp {
6579e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
6580552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6581552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6582552f7358SJed Brown   PetscInt        cind = 0, k;
6583552f7358SJed Brown 
6584552f7358SJed Brown   PetscFunctionBegin;
658508401ef6SPierre Jolivet   PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
65869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
65879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6588552f7358SJed Brown   if (!cdof || setBC) {
658905586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
659005586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
659105586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
659205586334SMatthew G. Knepley 
659305586334SMatthew G. Knepley       indices[ind] = off + k;
6594552f7358SJed Brown     }
6595552f7358SJed Brown   } else {
65969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
65974acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
659805586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
659905586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
660005586334SMatthew G. Knepley 
66014acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
66024acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
660305586334SMatthew G. Knepley         indices[ind] = -(off+k+1);
66044acb8e1eSToby Isaac         ++cind;
66054acb8e1eSToby Isaac       } else {
660636fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
6607552f7358SJed Brown       }
6608552f7358SJed Brown     }
6609552f7358SJed Brown   }
6610e6ccafaeSMatthew G Knepley   *loff += dof;
6611552f7358SJed Brown   PetscFunctionReturn(0);
6612552f7358SJed Brown }
6613552f7358SJed Brown 
66147e29afd2SMatthew G. Knepley /*
661536fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
66167e29afd2SMatthew G. Knepley 
661736fa2b79SJed Brown  Input Parameters:
661836fa2b79SJed Brown + section - a section (global or local)
661936fa2b79SJed Brown - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
662036fa2b79SJed Brown . point - point within section
662136fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
662236fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
662336fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
662436fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
662536fa2b79SJed Brown . permsoff - offset
662636fa2b79SJed Brown - indperm - index permutation
662736fa2b79SJed Brown 
662836fa2b79SJed Brown  Output Parameter:
662936fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
663036fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
663136fa2b79SJed Brown 
663236fa2b79SJed Brown  Notes:
663336fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
663436fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
663536fa2b79SJed Brown  in the local vector.
663636fa2b79SJed Brown 
663736fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
663836fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
663936fa2b79SJed Brown 
664036fa2b79SJed Brown  Developer Note:
664136fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
664236fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
664336fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
664436fa2b79SJed Brown 
664536fa2b79SJed Brown  Example:
664636fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
664736fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
664836fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
664936fa2b79SJed 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.
665036fa2b79SJed Brown 
665136fa2b79SJed Brown  Level: developer
66527e29afd2SMatthew G. Knepley */
665336fa2b79SJed 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[])
6654a6dfd86eSKarl Rupp {
6655552f7358SJed Brown   PetscInt       numFields, foff, f;
6656552f7358SJed Brown 
6657552f7358SJed Brown   PetscFunctionBegin;
665808401ef6SPierre Jolivet   PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
66599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6660552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
66614acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
6662552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
66634acb8e1eSToby Isaac     PetscInt        cind = 0, b;
66644acb8e1eSToby Isaac     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6665552f7358SJed Brown 
66669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
66679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
6668552f7358SJed Brown     if (!cfdof || setBC) {
666905586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
667005586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
667105586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
667205586334SMatthew G. Knepley 
667305586334SMatthew G. Knepley         indices[ind] = off+foff+b;
667405586334SMatthew G. Knepley       }
6675552f7358SJed Brown     } else {
66769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
667705586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
667805586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
667905586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
668005586334SMatthew G. Knepley 
66814acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
668205586334SMatthew G. Knepley           indices[ind] = -(off+foff+b+1);
6683552f7358SJed Brown           ++cind;
6684552f7358SJed Brown         } else {
668536fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6686552f7358SJed Brown         }
6687552f7358SJed Brown       }
6688552f7358SJed Brown     }
668936fa2b79SJed Brown     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6690552f7358SJed Brown     foffs[f] += fdof;
6691552f7358SJed Brown   }
6692552f7358SJed Brown   PetscFunctionReturn(0);
6693552f7358SJed Brown }
6694552f7358SJed Brown 
66957e29afd2SMatthew G. Knepley /*
66967e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
66977e29afd2SMatthew G. Knepley 
66987e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
6699645102dcSJed Brown 
6700645102dcSJed Brown  Notes:
6701645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6702645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
67037e29afd2SMatthew G. Knepley */
6704645102dcSJed Brown static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
67057e29afd2SMatthew G. Knepley {
67067e29afd2SMatthew G. Knepley   PetscInt       numFields, foff, f;
67077e29afd2SMatthew G. Knepley 
67087e29afd2SMatthew G. Knepley   PetscFunctionBegin;
67099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
67107e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
67117e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
67127e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
67137e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
67147e29afd2SMatthew G. Knepley     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
67157e29afd2SMatthew G. Knepley 
67169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
67179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
67189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
6719645102dcSJed Brown     if (!cfdof) {
672005586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
672105586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
672205586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
672305586334SMatthew G. Knepley 
672405586334SMatthew G. Knepley         indices[ind] = foff+b;
672505586334SMatthew G. Knepley       }
67267e29afd2SMatthew G. Knepley     } else {
67279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
672805586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
672905586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
673005586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
673105586334SMatthew G. Knepley 
67327e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
673305586334SMatthew G. Knepley           indices[ind] = -(foff+b+1);
67347e29afd2SMatthew G. Knepley           ++cind;
67357e29afd2SMatthew G. Knepley         } else {
673605586334SMatthew G. Knepley           indices[ind] = foff+b-cind;
67377e29afd2SMatthew G. Knepley         }
67387e29afd2SMatthew G. Knepley       }
67397e29afd2SMatthew G. Knepley     }
67407e29afd2SMatthew G. Knepley     foffs[f] += fdof;
67417e29afd2SMatthew G. Knepley   }
67427e29afd2SMatthew G. Knepley   PetscFunctionReturn(0);
67437e29afd2SMatthew G. Knepley }
67447e29afd2SMatthew G. Knepley 
67454acb8e1eSToby 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)
6746d3d1a6afSToby Isaac {
6747d3d1a6afSToby Isaac   Mat             cMat;
6748d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
6749d3d1a6afSToby Isaac   IS              aIS;
6750d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
6751d3d1a6afSToby Isaac   const PetscInt  *anchors;
6752e17c06e0SMatthew G. Knepley   PetscInt        numFields, f, p, q, newP = 0;
6753d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
6754d3d1a6afSToby Isaac   PetscInt        *newPoints, *indices, *newIndices;
6755d3d1a6afSToby Isaac   PetscInt        maxAnchor, maxDof;
6756d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
6757d3d1a6afSToby Isaac   PetscInt        *pointMatOffsets[32];
6758d3d1a6afSToby Isaac   PetscInt        *newPointOffsets[32];
6759d3d1a6afSToby Isaac   PetscScalar     *pointMat[32];
67606ecaa68aSToby Isaac   PetscScalar     *newValues=NULL,*tmpValues;
6761d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
6762d3d1a6afSToby Isaac 
6763d3d1a6afSToby Isaac   PetscFunctionBegin;
6764d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6765d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
67669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6767d3d1a6afSToby Isaac 
67689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS));
6769d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
6770d3d1a6afSToby Isaac   if (aSec) {
67719566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
67729566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS,&anchors));
67739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd));
6774d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
6775d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
6776d3d1a6afSToby Isaac      * into the global matrix anyway) */
6777d3d1a6afSToby Isaac     for (p = 0; p < 2*numPoints; p+=2) {
6778d3d1a6afSToby Isaac       PetscInt b    = points[p];
67794b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6780d3d1a6afSToby Isaac 
67819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,b,&bSecDof));
67824b2f2278SToby Isaac       if (!bSecDof) {
67834b2f2278SToby Isaac         continue;
67844b2f2278SToby Isaac       }
6785d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
67869566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,b,&bDof));
6787d3d1a6afSToby Isaac       }
6788d3d1a6afSToby Isaac       if (bDof) {
6789d3d1a6afSToby Isaac         /* this point is constrained */
6790d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
6791d3d1a6afSToby Isaac         PetscInt bOff, q;
6792d3d1a6afSToby Isaac 
6793d3d1a6afSToby Isaac         anyConstrained = PETSC_TRUE;
6794d3d1a6afSToby Isaac         newNumPoints  += bDof;
67959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,b,&bOff));
6796d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
6797d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q];
6798d3d1a6afSToby Isaac           PetscInt aDof;
6799d3d1a6afSToby Isaac 
68009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,a,&aDof));
6801d3d1a6afSToby Isaac           newNumIndices += aDof;
6802d3d1a6afSToby Isaac           for (f = 0; f < numFields; ++f) {
6803d3d1a6afSToby Isaac             PetscInt fDof;
6804d3d1a6afSToby Isaac 
68059566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
6806d3d1a6afSToby Isaac             newOffsets[f+1] += fDof;
6807d3d1a6afSToby Isaac           }
6808d3d1a6afSToby Isaac         }
6809d3d1a6afSToby Isaac       }
6810d3d1a6afSToby Isaac       else {
6811d3d1a6afSToby Isaac         /* this point is not constrained */
6812d3d1a6afSToby Isaac         newNumPoints++;
68134b2f2278SToby Isaac         newNumIndices += bSecDof;
6814d3d1a6afSToby Isaac         for (f = 0; f < numFields; ++f) {
6815d3d1a6afSToby Isaac           PetscInt fDof;
6816d3d1a6afSToby Isaac 
68179566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
6818d3d1a6afSToby Isaac           newOffsets[f+1] += fDof;
6819d3d1a6afSToby Isaac         }
6820d3d1a6afSToby Isaac       }
6821d3d1a6afSToby Isaac     }
6822d3d1a6afSToby Isaac   }
6823d3d1a6afSToby Isaac   if (!anyConstrained) {
682472b80496SMatthew G. Knepley     if (outNumPoints)  *outNumPoints  = 0;
682572b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
682672b80496SMatthew G. Knepley     if (outPoints)     *outPoints     = NULL;
682772b80496SMatthew G. Knepley     if (outValues)     *outValues     = NULL;
68289566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors));
6829d3d1a6afSToby Isaac     PetscFunctionReturn(0);
6830d3d1a6afSToby Isaac   }
6831d3d1a6afSToby Isaac 
68326ecaa68aSToby Isaac   if (outNumPoints)  *outNumPoints  = newNumPoints;
68336ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
68346ecaa68aSToby Isaac 
6835f13f9184SToby Isaac   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6836d3d1a6afSToby Isaac 
68376ecaa68aSToby Isaac   if (!outPoints && !outValues) {
68386ecaa68aSToby Isaac     if (offsets) {
68396ecaa68aSToby Isaac       for (f = 0; f <= numFields; f++) {
68406ecaa68aSToby Isaac         offsets[f] = newOffsets[f];
68416ecaa68aSToby Isaac       }
68426ecaa68aSToby Isaac     }
68439566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors));
68446ecaa68aSToby Isaac     PetscFunctionReturn(0);
68456ecaa68aSToby Isaac   }
68466ecaa68aSToby Isaac 
68471dca8a05SBarry 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);
6848d3d1a6afSToby Isaac 
68499566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
6850d3d1a6afSToby Isaac 
6851d3d1a6afSToby Isaac   /* workspaces */
6852d3d1a6afSToby Isaac   if (numFields) {
6853d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
68549566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]));
68559566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]));
6856d3d1a6afSToby Isaac     }
6857d3d1a6afSToby Isaac   }
6858d3d1a6afSToby Isaac   else {
68599566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]));
68609566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]));
6861d3d1a6afSToby Isaac   }
6862d3d1a6afSToby Isaac 
6863d3d1a6afSToby Isaac   /* get workspaces for the point-to-point matrices */
6864d3d1a6afSToby Isaac   if (numFields) {
68654b2f2278SToby Isaac     PetscInt totalOffset, totalMatOffset;
68664b2f2278SToby Isaac 
6867d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
6868d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
68694b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6870d3d1a6afSToby Isaac 
68719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,b,&bSecDof));
68724b2f2278SToby Isaac       if (!bSecDof) {
68734b2f2278SToby Isaac         for (f = 0; f < numFields; f++) {
68744b2f2278SToby Isaac           newPointOffsets[f][p + 1] = 0;
68754b2f2278SToby Isaac           pointMatOffsets[f][p + 1] = 0;
68764b2f2278SToby Isaac         }
68774b2f2278SToby Isaac         continue;
68784b2f2278SToby Isaac       }
6879d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
68809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
6881d3d1a6afSToby Isaac       }
6882d3d1a6afSToby Isaac       if (bDof) {
6883d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
6884d3d1a6afSToby Isaac           PetscInt fDof, q, bOff, allFDof = 0;
6885d3d1a6afSToby Isaac 
68869566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
68879566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
6888d3d1a6afSToby Isaac           for (q = 0; q < bDof; q++) {
6889d3d1a6afSToby Isaac             PetscInt a = anchors[bOff + q];
6890d3d1a6afSToby Isaac             PetscInt aFDof;
6891d3d1a6afSToby Isaac 
68929566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
6893d3d1a6afSToby Isaac             allFDof += aFDof;
6894d3d1a6afSToby Isaac           }
6895d3d1a6afSToby Isaac           newPointOffsets[f][p+1] = allFDof;
6896d3d1a6afSToby Isaac           pointMatOffsets[f][p+1] = fDof * allFDof;
6897d3d1a6afSToby Isaac         }
6898d3d1a6afSToby Isaac       }
6899d3d1a6afSToby Isaac       else {
6900d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
6901d3d1a6afSToby Isaac           PetscInt fDof;
6902d3d1a6afSToby Isaac 
69039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
6904d3d1a6afSToby Isaac           newPointOffsets[f][p+1] = fDof;
6905d3d1a6afSToby Isaac           pointMatOffsets[f][p+1] = 0;
6906d3d1a6afSToby Isaac         }
6907d3d1a6afSToby Isaac       }
6908d3d1a6afSToby Isaac     }
69094b2f2278SToby Isaac     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
69104b2f2278SToby Isaac       newPointOffsets[f][0] = totalOffset;
69114b2f2278SToby Isaac       pointMatOffsets[f][0] = totalMatOffset;
6912d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
6913d3d1a6afSToby Isaac         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6914d3d1a6afSToby Isaac         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6915d3d1a6afSToby Isaac       }
691619f70fd5SToby Isaac       totalOffset    = newPointOffsets[f][numPoints];
691719f70fd5SToby Isaac       totalMatOffset = pointMatOffsets[f][numPoints];
69189566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]));
6919d3d1a6afSToby Isaac     }
6920d3d1a6afSToby Isaac   }
6921d3d1a6afSToby Isaac   else {
6922d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
6923d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
69244b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6925d3d1a6afSToby Isaac 
69269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,b,&bSecDof));
69274b2f2278SToby Isaac       if (!bSecDof) {
69284b2f2278SToby Isaac         newPointOffsets[0][p + 1] = 0;
69294b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = 0;
69304b2f2278SToby Isaac         continue;
69314b2f2278SToby Isaac       }
6932d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
69339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
6934d3d1a6afSToby Isaac       }
6935d3d1a6afSToby Isaac       if (bDof) {
69364b2f2278SToby Isaac         PetscInt bOff, q, allDof = 0;
6937d3d1a6afSToby Isaac 
69389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
6939d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
6940d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aDof;
6941d3d1a6afSToby Isaac 
69429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
6943d3d1a6afSToby Isaac           allDof += aDof;
6944d3d1a6afSToby Isaac         }
6945d3d1a6afSToby Isaac         newPointOffsets[0][p+1] = allDof;
69464b2f2278SToby Isaac         pointMatOffsets[0][p+1] = bSecDof * allDof;
6947d3d1a6afSToby Isaac       }
6948d3d1a6afSToby Isaac       else {
69494b2f2278SToby Isaac         newPointOffsets[0][p+1] = bSecDof;
6950d3d1a6afSToby Isaac         pointMatOffsets[0][p+1] = 0;
6951d3d1a6afSToby Isaac       }
6952d3d1a6afSToby Isaac     }
6953d3d1a6afSToby Isaac     newPointOffsets[0][0] = 0;
6954d3d1a6afSToby Isaac     pointMatOffsets[0][0] = 0;
6955d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
6956d3d1a6afSToby Isaac       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6957d3d1a6afSToby Isaac       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6958d3d1a6afSToby Isaac     }
69599566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]));
6960d3d1a6afSToby Isaac   }
6961d3d1a6afSToby Isaac 
69626ecaa68aSToby Isaac   /* output arrays */
69639566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints));
69646ecaa68aSToby Isaac 
6965d3d1a6afSToby Isaac   /* get the point-to-point matrices; construct newPoints */
69669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
69679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
69689566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices));
69699566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices));
6970d3d1a6afSToby Isaac   if (numFields) {
6971d3d1a6afSToby Isaac     for (p = 0, newP = 0; p < numPoints; p++) {
6972d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
6973d3d1a6afSToby Isaac       PetscInt o    = points[2*p+1];
69744b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
6975d3d1a6afSToby Isaac 
69769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
69774b2f2278SToby Isaac       if (!bSecDof) {
69784b2f2278SToby Isaac         continue;
69794b2f2278SToby Isaac       }
6980d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
69819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
6982d3d1a6afSToby Isaac       }
6983d3d1a6afSToby Isaac       if (bDof) {
6984d3d1a6afSToby Isaac         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6985d3d1a6afSToby Isaac 
6986d3d1a6afSToby Isaac         fStart[0] = 0;
6987d3d1a6afSToby Isaac         fEnd[0]   = 0;
6988d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
6989d3d1a6afSToby Isaac           PetscInt fDof;
6990d3d1a6afSToby Isaac 
69919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
6992d3d1a6afSToby Isaac           fStart[f+1] = fStart[f] + fDof;
6993d3d1a6afSToby Isaac           fEnd[f+1]   = fStart[f+1];
6994d3d1a6afSToby Isaac         }
69959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
69969566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
6997d3d1a6afSToby Isaac 
6998d3d1a6afSToby Isaac         fAnchorStart[0] = 0;
6999d3d1a6afSToby Isaac         fAnchorEnd[0]   = 0;
7000d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7001d3d1a6afSToby Isaac           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7002d3d1a6afSToby Isaac 
7003d3d1a6afSToby Isaac           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
7004d3d1a6afSToby Isaac           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
7005d3d1a6afSToby Isaac         }
70069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7007d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7008d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7009d3d1a6afSToby Isaac 
7010d3d1a6afSToby 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 */
7011d3d1a6afSToby Isaac           newPoints[2*(newP + q)]     = a;
7012d3d1a6afSToby Isaac           newPoints[2*(newP + q) + 1] = 0;
70139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
70149566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7015d3d1a6afSToby Isaac         }
7016d3d1a6afSToby Isaac         newP += bDof;
7017d3d1a6afSToby Isaac 
70186ecaa68aSToby Isaac         if (outValues) {
7019d3d1a6afSToby Isaac           /* get the point-to-point submatrix */
7020d3d1a6afSToby Isaac           for (f = 0; f < numFields; f++) {
70219566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]));
7022d3d1a6afSToby Isaac           }
7023d3d1a6afSToby Isaac         }
70246ecaa68aSToby Isaac       }
7025d3d1a6afSToby Isaac       else {
7026d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7027d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7028d3d1a6afSToby Isaac         newP++;
7029d3d1a6afSToby Isaac       }
7030d3d1a6afSToby Isaac     }
7031d3d1a6afSToby Isaac   } else {
7032d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7033d3d1a6afSToby Isaac       PetscInt b    = points[2*p];
7034d3d1a6afSToby Isaac       PetscInt o    = points[2*p+1];
70354b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7036d3d1a6afSToby Isaac 
70379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
70384b2f2278SToby Isaac       if (!bSecDof) {
70394b2f2278SToby Isaac         continue;
70404b2f2278SToby Isaac       }
7041d3d1a6afSToby Isaac       if (b >= aStart && b < aEnd) {
70429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7043d3d1a6afSToby Isaac       }
7044d3d1a6afSToby Isaac       if (bDof) {
7045d3d1a6afSToby Isaac         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7046d3d1a6afSToby Isaac 
70479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
70489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7049d3d1a6afSToby Isaac 
70509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset (aSec, b, &bOff));
7051d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7052d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7053d3d1a6afSToby Isaac 
7054d3d1a6afSToby 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 */
7055d3d1a6afSToby Isaac 
7056d3d1a6afSToby Isaac           newPoints[2*(newP + q)]     = a;
7057d3d1a6afSToby Isaac           newPoints[2*(newP + q) + 1] = 0;
70589566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
70599566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7060d3d1a6afSToby Isaac         }
7061d3d1a6afSToby Isaac         newP += bDof;
7062d3d1a6afSToby Isaac 
7063d3d1a6afSToby Isaac         /* get the point-to-point submatrix */
70646ecaa68aSToby Isaac         if (outValues) {
70659566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]));
7066d3d1a6afSToby Isaac         }
70676ecaa68aSToby Isaac       }
7068d3d1a6afSToby Isaac       else {
7069d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7070d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7071d3d1a6afSToby Isaac         newP++;
7072d3d1a6afSToby Isaac       }
7073d3d1a6afSToby Isaac     }
7074d3d1a6afSToby Isaac   }
7075d3d1a6afSToby Isaac 
70766ecaa68aSToby Isaac   if (outValues) {
70779566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues));
70789566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices));
7079d3d1a6afSToby Isaac     /* multiply constraints on the right */
7080d3d1a6afSToby Isaac     if (numFields) {
7081d3d1a6afSToby Isaac       for (f = 0; f < numFields; f++) {
7082d3d1a6afSToby Isaac         PetscInt oldOff = offsets[f];
7083d3d1a6afSToby Isaac 
7084d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7085d3d1a6afSToby Isaac           PetscInt cStart = newPointOffsets[f][p];
7086d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7087d3d1a6afSToby Isaac           PetscInt c, r, k;
7088d3d1a6afSToby Isaac           PetscInt dof;
7089d3d1a6afSToby Isaac 
70909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,b,f,&dof));
70914b2f2278SToby Isaac           if (!dof) {
70924b2f2278SToby Isaac             continue;
70934b2f2278SToby Isaac           }
7094d3d1a6afSToby Isaac           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7095d3d1a6afSToby Isaac             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7096d3d1a6afSToby Isaac             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7097d3d1a6afSToby Isaac 
7098d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7099d3d1a6afSToby Isaac               for (c = 0; c < nCols; c++) {
7100d3d1a6afSToby Isaac                 for (k = 0; k < dof; k++) {
71014acb8e1eSToby Isaac                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7102d3d1a6afSToby Isaac                 }
7103d3d1a6afSToby Isaac               }
7104d3d1a6afSToby Isaac             }
7105d3d1a6afSToby Isaac           }
7106d3d1a6afSToby Isaac           else {
7107d3d1a6afSToby Isaac             /* copy this column as is */
7108d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7109d3d1a6afSToby Isaac               for (c = 0; c < dof; c++) {
7110d3d1a6afSToby Isaac                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7111d3d1a6afSToby Isaac               }
7112d3d1a6afSToby Isaac             }
7113d3d1a6afSToby Isaac           }
7114d3d1a6afSToby Isaac           oldOff += dof;
7115d3d1a6afSToby Isaac         }
7116d3d1a6afSToby Isaac       }
7117d3d1a6afSToby Isaac     }
7118d3d1a6afSToby Isaac     else {
7119d3d1a6afSToby Isaac       PetscInt oldOff = 0;
7120d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7121d3d1a6afSToby Isaac         PetscInt cStart = newPointOffsets[0][p];
7122d3d1a6afSToby Isaac         PetscInt b      = points[2 * p];
7123d3d1a6afSToby Isaac         PetscInt c, r, k;
7124d3d1a6afSToby Isaac         PetscInt dof;
7125d3d1a6afSToby Isaac 
71269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section,b,&dof));
71274b2f2278SToby Isaac         if (!dof) {
71284b2f2278SToby Isaac           continue;
71294b2f2278SToby Isaac         }
7130d3d1a6afSToby Isaac         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7131d3d1a6afSToby Isaac           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7132d3d1a6afSToby Isaac           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7133d3d1a6afSToby Isaac 
7134d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7135d3d1a6afSToby Isaac             for (c = 0; c < nCols; c++) {
7136d3d1a6afSToby Isaac               for (k = 0; k < dof; k++) {
7137d3d1a6afSToby Isaac                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7138d3d1a6afSToby Isaac               }
7139d3d1a6afSToby Isaac             }
7140d3d1a6afSToby Isaac           }
7141d3d1a6afSToby Isaac         }
7142d3d1a6afSToby Isaac         else {
7143d3d1a6afSToby Isaac           /* copy this column as is */
7144d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7145d3d1a6afSToby Isaac             for (c = 0; c < dof; c++) {
7146d3d1a6afSToby Isaac               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7147d3d1a6afSToby Isaac             }
7148d3d1a6afSToby Isaac           }
7149d3d1a6afSToby Isaac         }
7150d3d1a6afSToby Isaac         oldOff += dof;
7151d3d1a6afSToby Isaac       }
7152d3d1a6afSToby Isaac     }
7153d3d1a6afSToby Isaac 
71546ecaa68aSToby Isaac     if (multiplyLeft) {
71559566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues));
71569566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices));
7157d3d1a6afSToby Isaac       /* multiply constraints transpose on the left */
7158d3d1a6afSToby Isaac       if (numFields) {
7159d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7160d3d1a6afSToby Isaac           PetscInt oldOff = offsets[f];
7161d3d1a6afSToby Isaac 
7162d3d1a6afSToby Isaac           for (p = 0; p < numPoints; p++) {
7163d3d1a6afSToby Isaac             PetscInt rStart = newPointOffsets[f][p];
7164d3d1a6afSToby Isaac             PetscInt b      = points[2 * p];
7165d3d1a6afSToby Isaac             PetscInt c, r, k;
7166d3d1a6afSToby Isaac             PetscInt dof;
7167d3d1a6afSToby Isaac 
71689566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,b,f,&dof));
7169d3d1a6afSToby Isaac             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7170d3d1a6afSToby Isaac               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7171d3d1a6afSToby Isaac               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7172d3d1a6afSToby Isaac 
7173d3d1a6afSToby Isaac               for (r = 0; r < nRows; r++) {
7174d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7175d3d1a6afSToby Isaac                   for (k = 0; k < dof; k++) {
7176d3d1a6afSToby Isaac                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7177d3d1a6afSToby Isaac                   }
7178d3d1a6afSToby Isaac                 }
7179d3d1a6afSToby Isaac               }
7180d3d1a6afSToby Isaac             }
7181d3d1a6afSToby Isaac             else {
7182d3d1a6afSToby Isaac               /* copy this row as is */
7183d3d1a6afSToby Isaac               for (r = 0; r < dof; r++) {
7184d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7185d3d1a6afSToby Isaac                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7186d3d1a6afSToby Isaac                 }
7187d3d1a6afSToby Isaac               }
7188d3d1a6afSToby Isaac             }
7189d3d1a6afSToby Isaac             oldOff += dof;
7190d3d1a6afSToby Isaac           }
7191d3d1a6afSToby Isaac         }
7192d3d1a6afSToby Isaac       }
7193d3d1a6afSToby Isaac       else {
7194d3d1a6afSToby Isaac         PetscInt oldOff = 0;
7195d3d1a6afSToby Isaac 
7196d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7197d3d1a6afSToby Isaac           PetscInt rStart = newPointOffsets[0][p];
7198d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7199d3d1a6afSToby Isaac           PetscInt c, r, k;
7200d3d1a6afSToby Isaac           PetscInt dof;
7201d3d1a6afSToby Isaac 
72029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,b,&dof));
7203d3d1a6afSToby Isaac           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7204d3d1a6afSToby Isaac             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7205d3d1a6afSToby Isaac             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7206d3d1a6afSToby Isaac 
7207d3d1a6afSToby Isaac             for (r = 0; r < nRows; r++) {
7208d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7209d3d1a6afSToby Isaac                 for (k = 0; k < dof; k++) {
7210d3d1a6afSToby Isaac                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7211d3d1a6afSToby Isaac                 }
7212d3d1a6afSToby Isaac               }
7213d3d1a6afSToby Isaac             }
7214d3d1a6afSToby Isaac           }
7215d3d1a6afSToby Isaac           else {
7216d3d1a6afSToby Isaac             /* copy this row as is */
72179fc93327SToby Isaac             for (r = 0; r < dof; r++) {
7218d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7219d3d1a6afSToby Isaac                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7220d3d1a6afSToby Isaac               }
7221d3d1a6afSToby Isaac             }
7222d3d1a6afSToby Isaac           }
7223d3d1a6afSToby Isaac           oldOff += dof;
7224d3d1a6afSToby Isaac         }
7225d3d1a6afSToby Isaac       }
7226d3d1a6afSToby Isaac 
72279566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues));
72286ecaa68aSToby Isaac     }
72296ecaa68aSToby Isaac     else {
72306ecaa68aSToby Isaac       newValues = tmpValues;
72316ecaa68aSToby Isaac     }
72326ecaa68aSToby Isaac   }
72336ecaa68aSToby Isaac 
7234d3d1a6afSToby Isaac   /* clean up */
72359566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices));
72369566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices));
72376ecaa68aSToby Isaac 
7238d3d1a6afSToby Isaac   if (numFields) {
7239d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
72409566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]));
72419566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]));
72429566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]));
7243d3d1a6afSToby Isaac     }
7244d3d1a6afSToby Isaac   }
7245d3d1a6afSToby Isaac   else {
72469566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]));
72479566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]));
72489566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]));
7249d3d1a6afSToby Isaac   }
72509566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
7251d3d1a6afSToby Isaac 
7252d3d1a6afSToby Isaac   /* output */
72536ecaa68aSToby Isaac   if (outPoints) {
7254d3d1a6afSToby Isaac     *outPoints = newPoints;
72556ecaa68aSToby Isaac   }
72566ecaa68aSToby Isaac   else {
72579566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints));
72586ecaa68aSToby Isaac   }
725931620726SToby Isaac   if (outValues) {
7260d3d1a6afSToby Isaac     *outValues = newValues;
72616ecaa68aSToby Isaac   }
72626ecaa68aSToby Isaac   for (f = 0; f <= numFields; f++) {
7263d3d1a6afSToby Isaac     offsets[f] = newOffsets[f];
7264d3d1a6afSToby Isaac   }
7265d3d1a6afSToby Isaac   PetscFunctionReturn(0);
7266d3d1a6afSToby Isaac }
7267d3d1a6afSToby Isaac 
72684a1e0b3eSMatthew G. Knepley /*@C
726971f0bbf9SMatthew G. Knepley   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
72707cd05799SMatthew G. Knepley 
72717cd05799SMatthew G. Knepley   Not collective
72727cd05799SMatthew G. Knepley 
72737cd05799SMatthew G. Knepley   Input Parameters:
72747cd05799SMatthew G. Knepley + dm         - The DM
727571f0bbf9SMatthew G. Knepley . section    - The PetscSection describing the points (a local section)
727671f0bbf9SMatthew G. Knepley . idxSection - The PetscSection from which to obtain indices (may be local or global)
727771f0bbf9SMatthew G. Knepley . point      - The point defining the closure
727871f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
72797cd05799SMatthew G. Knepley 
728071f0bbf9SMatthew G. Knepley   Output Parameters:
728171f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
728271f0bbf9SMatthew G. Knepley . indices    - The dof indices
728371f0bbf9SMatthew G. Knepley . outOffsets - Array to write the field offsets into, or NULL
728471f0bbf9SMatthew G. Knepley - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
72857cd05799SMatthew G. Knepley 
728636fa2b79SJed Brown   Notes:
728736fa2b79SJed Brown   Must call DMPlexRestoreClosureIndices() to free allocated memory
728836fa2b79SJed Brown 
728936fa2b79SJed Brown   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
729036fa2b79SJed Brown   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
729136fa2b79SJed Brown   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
729236fa2b79SJed Brown   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
729336fa2b79SJed Brown   indices (with the above semantics) are implied.
72947cd05799SMatthew G. Knepley 
72957cd05799SMatthew G. Knepley   Level: advanced
72967cd05799SMatthew G. Knepley 
7297db781477SPatrick Sanan .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
72984a1e0b3eSMatthew G. Knepley @*/
729971f0bbf9SMatthew G. Knepley PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
730071f0bbf9SMatthew G. Knepley                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
73017773e69fSMatthew G. Knepley {
730271f0bbf9SMatthew G. Knepley   /* Closure ordering */
73037773e69fSMatthew G. Knepley   PetscSection        clSection;
73047773e69fSMatthew G. Knepley   IS                  clPoints;
730571f0bbf9SMatthew G. Knepley   const PetscInt     *clp;
730671f0bbf9SMatthew G. Knepley   PetscInt           *points;
730771f0bbf9SMatthew G. Knepley   const PetscInt     *clperm = NULL;
730871f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
73094acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
731071f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
731171f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
731271f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
731371f0bbf9SMatthew G. Knepley   PetscInt           *pointsC = NULL;
731471f0bbf9SMatthew G. Knepley   PetscScalar        *valuesC = NULL;
731571f0bbf9SMatthew G. Knepley   PetscInt            NclC, NiC;
731671f0bbf9SMatthew G. Knepley 
731771f0bbf9SMatthew G. Knepley   PetscInt           *idx;
731871f0bbf9SMatthew G. Knepley   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
731971f0bbf9SMatthew G. Knepley   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
73207773e69fSMatthew G. Knepley 
732171f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
73227773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
73237773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
732436fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7325dadcf809SJacob Faibussowitsch   if (numIndices) PetscValidIntPointer(numIndices, 6);
732671f0bbf9SMatthew G. Knepley   if (indices)    PetscValidPointer(indices, 7);
7327dadcf809SJacob Faibussowitsch   if (outOffsets) PetscValidIntPointer(outOffsets, 8);
732871f0bbf9SMatthew G. Knepley   if (values)     PetscValidPointer(values, 9);
73299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
733063a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
73319566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
733271f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
73339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7334c459fbc1SJed Brown   if (useClPerm) {
7335c459fbc1SJed Brown     PetscInt depth, clsize;
73369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7337c459fbc1SJed Brown     for (clsize=0,p=0; p<Ncl; p++) {
7338c459fbc1SJed Brown       PetscInt dof;
73399566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2*p], &dof));
7340c459fbc1SJed Brown       clsize += dof;
7341c459fbc1SJed Brown     }
73429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm));
7343c459fbc1SJed Brown   }
734471f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
734571f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl*2; p += 2) {
73467773e69fSMatthew G. Knepley     PetscInt dof, fdof;
73477773e69fSMatthew G. Knepley 
73489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
73497773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
73509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
73517773e69fSMatthew G. Knepley       offsets[f+1] += fdof;
73527773e69fSMatthew G. Knepley     }
735371f0bbf9SMatthew G. Knepley     Ni += dof;
73547773e69fSMatthew G. Knepley   }
73557773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
73561dca8a05SBarry 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);
735771f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
735871f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
73599566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
73609566063dSJacob Faibussowitsch     else    PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
736171f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
736271f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
736371f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
73646ecaa68aSToby Isaac 
736571f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
736671f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2*p], fdof;
736771f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
736871f0bbf9SMatthew G. Knepley 
73699566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
73709566063dSJacob Faibussowitsch         else     PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
737171f0bbf9SMatthew G. Knepley         if (flip) {
737271f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
737371f0bbf9SMatthew G. Knepley 
737471f0bbf9SMatthew G. Knepley           if (!valCopy) {
73759566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy));
737671f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
737771f0bbf9SMatthew G. Knepley             *values = valCopy;
737871f0bbf9SMatthew G. Knepley           }
737971f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
738071f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
738171f0bbf9SMatthew G. Knepley 
738271f0bbf9SMatthew G. Knepley             for (k = 0; k < Ni; ++k) {
738371f0bbf9SMatthew G. Knepley               valCopy[Ni * (foffset + i) + k] *= fval;
738471f0bbf9SMatthew G. Knepley               valCopy[Ni * k + (foffset + i)] *= fval;
73856ecaa68aSToby Isaac             }
73866ecaa68aSToby Isaac           }
738771f0bbf9SMatthew G. Knepley         }
738871f0bbf9SMatthew G. Knepley         foffset += fdof;
738971f0bbf9SMatthew G. Knepley       }
739071f0bbf9SMatthew G. Knepley     }
739171f0bbf9SMatthew G. Knepley   }
739271f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
73939566063dSJacob Faibussowitsch   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
739471f0bbf9SMatthew G. Knepley   if (NclC) {
73959566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy));
739671f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
73979566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
73989566063dSJacob Faibussowitsch       else    PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
739971f0bbf9SMatthew G. Knepley     }
740071f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
74019566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
74029566063dSJacob Faibussowitsch       else    PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
740371f0bbf9SMatthew G. Knepley     }
74049566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
740571f0bbf9SMatthew G. Knepley     Ncl     = NclC;
740671f0bbf9SMatthew G. Knepley     Ni      = NiC;
740771f0bbf9SMatthew G. Knepley     points  = pointsC;
740871f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
740971f0bbf9SMatthew G. Knepley   }
741071f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
74119566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
741271f0bbf9SMatthew G. Knepley   if (Nf) {
741371f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
741471f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
741571f0bbf9SMatthew G. Knepley 
741671f0bbf9SMatthew G. Knepley     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
74179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
741871f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
741971f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
742071f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p*2];
742171f0bbf9SMatthew G. Knepley 
74229566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
74237773e69fSMatthew G. Knepley       }
74247773e69fSMatthew G. Knepley     } else {
742571f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
742671f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p*2];
742771f0bbf9SMatthew G. Knepley 
74289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
742971f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
743071f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
743171f0bbf9SMatthew G. Knepley          * global section. */
74329566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
743371f0bbf9SMatthew G. Knepley       }
743471f0bbf9SMatthew G. Knepley     }
743571f0bbf9SMatthew G. Knepley   } else {
743671f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
743771f0bbf9SMatthew G. Knepley 
743871f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
743971f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p*2];
74404acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
74414acb8e1eSToby Isaac 
74429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
744371f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
744471f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
74459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
74467773e69fSMatthew G. Knepley     }
74477773e69fSMatthew G. Knepley   }
744871f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
744971f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
74509566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
74519566063dSJacob Faibussowitsch     else    PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
74524acb8e1eSToby Isaac   }
745371f0bbf9SMatthew G. Knepley   if (NclC) {
74549566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC));
74557773e69fSMatthew G. Knepley   } else {
74569566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
74577773e69fSMatthew G. Knepley   }
745871f0bbf9SMatthew G. Knepley 
745971f0bbf9SMatthew G. Knepley   if (numIndices) *numIndices = Ni;
746071f0bbf9SMatthew G. Knepley   if (indices)    *indices    = idx;
74617773e69fSMatthew G. Knepley   PetscFunctionReturn(0);
74627773e69fSMatthew G. Knepley }
74637773e69fSMatthew G. Knepley 
74647cd05799SMatthew G. Knepley /*@C
746571f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
74667cd05799SMatthew G. Knepley 
74677cd05799SMatthew G. Knepley   Not collective
74687cd05799SMatthew G. Knepley 
74697cd05799SMatthew G. Knepley   Input Parameters:
74707cd05799SMatthew G. Knepley + dm         - The DM
747171f0bbf9SMatthew G. Knepley . section    - The PetscSection describing the points (a local section)
747271f0bbf9SMatthew G. Knepley . idxSection - The PetscSection from which to obtain indices (may be local or global)
747371f0bbf9SMatthew G. Knepley . point      - The point defining the closure
747471f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
747571f0bbf9SMatthew G. Knepley 
747671f0bbf9SMatthew G. Knepley   Output Parameters:
747771f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
747871f0bbf9SMatthew G. Knepley . indices    - The dof indices
747971f0bbf9SMatthew G. Knepley . outOffsets - Array to write the field offsets into, or NULL
748071f0bbf9SMatthew G. Knepley - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
748171f0bbf9SMatthew G. Knepley 
748271f0bbf9SMatthew G. Knepley   Notes:
748371f0bbf9SMatthew G. Knepley   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
748471f0bbf9SMatthew G. Knepley 
748571f0bbf9SMatthew G. Knepley   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
748671f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
748771f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
748871f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
748971f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
74907cd05799SMatthew G. Knepley 
74917cd05799SMatthew G. Knepley   Level: advanced
74927cd05799SMatthew G. Knepley 
7493db781477SPatrick Sanan .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
74947cd05799SMatthew G. Knepley @*/
749571f0bbf9SMatthew G. Knepley PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
749671f0bbf9SMatthew G. Knepley                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
74977773e69fSMatthew G. Knepley {
74987773e69fSMatthew G. Knepley   PetscFunctionBegin;
74997773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7500064a246eSJacob Faibussowitsch   PetscValidPointer(indices, 7);
75019566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
75027773e69fSMatthew G. Knepley   PetscFunctionReturn(0);
75037773e69fSMatthew G. Knepley }
75047773e69fSMatthew G. Knepley 
75057f5d1fdeSMatthew G. Knepley /*@C
75067f5d1fdeSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
75077f5d1fdeSMatthew G. Knepley 
75087f5d1fdeSMatthew G. Knepley   Not collective
75097f5d1fdeSMatthew G. Knepley 
75107f5d1fdeSMatthew G. Knepley   Input Parameters:
75117f5d1fdeSMatthew G. Knepley + dm - The DM
7512ebd6d717SJed Brown . section - The section describing the layout in v, or NULL to use the default section
7513ebd6d717SJed Brown . globalSection - The section describing the layout in v, or NULL to use the default global section
75147f5d1fdeSMatthew G. Knepley . A - The matrix
7515eaf898f9SPatrick Sanan . point - The point in the DM
75167f5d1fdeSMatthew G. Knepley . values - The array of values
75177f5d1fdeSMatthew G. Knepley - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
75187f5d1fdeSMatthew G. Knepley 
75197f5d1fdeSMatthew G. Knepley   Fortran Notes:
75207f5d1fdeSMatthew G. Knepley   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
75217f5d1fdeSMatthew G. Knepley 
75227f5d1fdeSMatthew G. Knepley   Level: intermediate
75237f5d1fdeSMatthew G. Knepley 
7524db781477SPatrick Sanan .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
75257f5d1fdeSMatthew G. Knepley @*/
75267c1f9639SMatthew G Knepley PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7527552f7358SJed Brown {
7528552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex*) dm->data;
7529552f7358SJed Brown   PetscInt          *indices;
753071f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
753171f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
7532552f7358SJed Brown   PetscErrorCode     ierr;
7533552f7358SJed Brown 
7534552f7358SJed Brown   PetscFunctionBegin;
7535552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
75369566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
75373dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
75389566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
75393dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
75403dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7541552f7358SJed Brown 
75429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
75430d644c17SKarl Rupp 
75449566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7545d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
75464a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7547552f7358SJed Brown   if (ierr) {
7548552f7358SJed Brown     PetscMPIInt    rank;
7549552f7358SJed Brown 
75509566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
75519566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
75529566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
75539566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
75549566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7555c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values");
7556552f7358SJed Brown   }
75574a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
75584a1e0b3eSMatthew G. Knepley     PetscInt i;
75599566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
756063a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
75619566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
75624a1e0b3eSMatthew G. Knepley   }
756371f0bbf9SMatthew G. Knepley 
75649566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values));
75659566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
756671f0bbf9SMatthew G. Knepley   PetscFunctionReturn(0);
75674acb8e1eSToby Isaac }
756871f0bbf9SMatthew G. Knepley 
75694a1e0b3eSMatthew G. Knepley /*@C
75704a1e0b3eSMatthew G. Knepley   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
75714a1e0b3eSMatthew G. Knepley 
75724a1e0b3eSMatthew G. Knepley   Not collective
75734a1e0b3eSMatthew G. Knepley 
75744a1e0b3eSMatthew G. Knepley   Input Parameters:
75754a1e0b3eSMatthew G. Knepley + dmRow - The DM for the row fields
75764a1e0b3eSMatthew G. Knepley . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
75774a1e0b3eSMatthew G. Knepley . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
75784a1e0b3eSMatthew G. Knepley . dmCol - The DM for the column fields
75794a1e0b3eSMatthew G. Knepley . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
75804a1e0b3eSMatthew G. Knepley . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
75814a1e0b3eSMatthew G. Knepley . A - The matrix
75824a1e0b3eSMatthew G. Knepley . point - The point in the DMs
75834a1e0b3eSMatthew G. Knepley . values - The array of values
75844a1e0b3eSMatthew G. Knepley - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
75854a1e0b3eSMatthew G. Knepley 
75864a1e0b3eSMatthew G. Knepley   Level: intermediate
75874a1e0b3eSMatthew G. Knepley 
7588db781477SPatrick Sanan .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
75894a1e0b3eSMatthew G. Knepley @*/
759071f0bbf9SMatthew 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)
759171f0bbf9SMatthew G. Knepley {
759271f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
759371f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
759471f0bbf9SMatthew G. Knepley   PetscInt           numIndicesRow, numIndicesCol;
759571f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
759671f0bbf9SMatthew G. Knepley   PetscErrorCode     ierr;
759771f0bbf9SMatthew G. Knepley 
759871f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
759971f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
76009566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
760171f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
76029566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
760371f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
760471f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
76059566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
760671f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
76079566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
760871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
760971f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
761071f0bbf9SMatthew G. Knepley 
76119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
76129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values));
761371f0bbf9SMatthew G. Knepley 
76149566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7615d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
76164a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
761771f0bbf9SMatthew G. Knepley   if (ierr) {
761871f0bbf9SMatthew G. Knepley     PetscMPIInt    rank;
761971f0bbf9SMatthew G. Knepley 
76209566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
76219566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
76229566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
76239566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
76249566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values));
76259566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7626d3d1a6afSToby Isaac   }
762771f0bbf9SMatthew G. Knepley 
76289566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values));
76299566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values));
76309566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7631552f7358SJed Brown   PetscFunctionReturn(0);
7632552f7358SJed Brown }
7633552f7358SJed Brown 
7634de41b84cSMatthew 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)
7635de41b84cSMatthew G. Knepley {
7636de41b84cSMatthew G. Knepley   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7637de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7638de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
7639de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
764017c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7641de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
7642412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
76434ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7644de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
7645de41b84cSMatthew G. Knepley 
7646de41b84cSMatthew G. Knepley   PetscFunctionBegin;
7647de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7648de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
76499566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
7650de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
76519566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
7652de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
76539566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
7654de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
76559566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
7656de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7657de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
76589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
765963a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
76609566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
76619566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
7662de41b84cSMatthew G. Knepley   /* Column indices */
76639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
76644ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
7665de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
7666de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
76679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
7668de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7669de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7670de41b84cSMatthew G. Knepley       cpoints[q*2]   = cpoints[p];
7671de41b84cSMatthew G. Knepley       cpoints[q*2+1] = cpoints[p+1];
7672de41b84cSMatthew G. Knepley       ++q;
7673de41b84cSMatthew G. Knepley     }
7674de41b84cSMatthew G. Knepley   }
7675de41b84cSMatthew G. Knepley   numCPoints = q;
7676de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7677de41b84cSMatthew G. Knepley     PetscInt fdof;
7678de41b84cSMatthew G. Knepley 
76799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
76804ca5e9f5SMatthew G. Knepley     if (!dof) continue;
7681de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
76829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
7683de41b84cSMatthew G. Knepley       coffsets[f+1] += fdof;
7684de41b84cSMatthew G. Knepley     }
7685de41b84cSMatthew G. Knepley     numCIndices += dof;
7686de41b84cSMatthew G. Knepley   }
7687de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7688de41b84cSMatthew G. Knepley   /* Row indices */
76899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
7690412e9a14SMatthew G. Knepley   {
7691012bc364SMatthew G. Knepley     DMPlexTransform tr;
7692012bc364SMatthew G. Knepley     DMPolytopeType *rct;
7693012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
7694012bc364SMatthew G. Knepley 
76959566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
76969566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
76979566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7698012bc364SMatthew G. Knepley     numSubcells = rsize[Nt-1];
76999566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
7700412e9a14SMatthew G. Knepley   }
77019566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints));
7702de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
7703de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
77049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
7705de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
77069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
7707de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints*2; p += 2) {
7708de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
77099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
77104ca5e9f5SMatthew G. Knepley         if (!dof) continue;
77114ca5e9f5SMatthew G. Knepley         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
77124ca5e9f5SMatthew G. Knepley         if (s < q) continue;
7713de41b84cSMatthew G. Knepley         ftotpoints[q*2]   = fpoints[p];
7714de41b84cSMatthew G. Knepley         ftotpoints[q*2+1] = fpoints[p+1];
7715de41b84cSMatthew G. Knepley         ++q;
7716de41b84cSMatthew G. Knepley       }
7717de41b84cSMatthew G. Knepley     }
77189566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
7719de41b84cSMatthew G. Knepley   }
7720de41b84cSMatthew G. Knepley   numFPoints = q;
7721de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7722de41b84cSMatthew G. Knepley     PetscInt fdof;
7723de41b84cSMatthew G. Knepley 
77249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
77254ca5e9f5SMatthew G. Knepley     if (!dof) continue;
7726de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
77279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
7728de41b84cSMatthew G. Knepley       foffsets[f+1] += fdof;
7729de41b84cSMatthew G. Knepley     }
7730de41b84cSMatthew G. Knepley     numFIndices += dof;
7731de41b84cSMatthew G. Knepley   }
7732de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7733de41b84cSMatthew G. Knepley 
77341dca8a05SBarry 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);
77351dca8a05SBarry 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);
77369566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
77379566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7738de41b84cSMatthew G. Knepley   if (numFields) {
77394acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
77404acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
77414acb8e1eSToby Isaac 
77424acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
77439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
77449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7745de41b84cSMatthew G. Knepley     }
77464acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
77479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
77489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
77494acb8e1eSToby Isaac     }
77504acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
77519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
77529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
77534acb8e1eSToby Isaac     }
77544acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
77559566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
77569566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
7757de41b84cSMatthew G. Knepley     }
7758de41b84cSMatthew G. Knepley   } else {
77594acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
77604acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
77614acb8e1eSToby Isaac 
77629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
77639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL));
77644acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
77654acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
77664acb8e1eSToby Isaac 
77679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
77689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
7769de41b84cSMatthew G. Knepley     }
77704acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
77714acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
77724acb8e1eSToby Isaac 
77739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
77749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
7775de41b84cSMatthew G. Knepley     }
77769566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
77779566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL));
7778de41b84cSMatthew G. Knepley   }
77799566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
77804acb8e1eSToby Isaac   /* TODO: flips */
7781d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
7782de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7783de41b84cSMatthew G. Knepley   if (ierr) {
7784de41b84cSMatthew G. Knepley     PetscMPIInt    rank;
7785de41b84cSMatthew G. Knepley 
77869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
77879566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
77889566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
77899566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
77909566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7791de41b84cSMatthew G. Knepley   }
77929566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints));
77939566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
77949566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
77959566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
7796de41b84cSMatthew G. Knepley   PetscFunctionReturn(0);
7797de41b84cSMatthew G. Knepley }
7798de41b84cSMatthew G. Knepley 
77997c927364SMatthew G. Knepley PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
78007c927364SMatthew G. Knepley {
78017c927364SMatthew G. Knepley   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
78027c927364SMatthew G. Knepley   PetscInt      *cpoints = NULL;
78037c927364SMatthew G. Knepley   PetscInt       foffsets[32], coffsets[32];
780417c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7805412e9a14SMatthew G. Knepley   DMPolytopeType ct;
78067c927364SMatthew G. Knepley   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
78077c927364SMatthew G. Knepley 
78087c927364SMatthew G. Knepley   PetscFunctionBegin;
78097c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
78107c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
78119566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
78127c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
78139566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
78147c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
78159566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
78167c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
78179566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
78187c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
78199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
782063a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
78219566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
78229566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
78237c927364SMatthew G. Knepley   /* Column indices */
78249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
78257c927364SMatthew G. Knepley   maxFPoints = numCPoints;
78267c927364SMatthew G. Knepley   /* Compress out points not in the section */
78277c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
78289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
78297c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
78307c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
78317c927364SMatthew G. Knepley       cpoints[q*2]   = cpoints[p];
78327c927364SMatthew G. Knepley       cpoints[q*2+1] = cpoints[p+1];
78337c927364SMatthew G. Knepley       ++q;
78347c927364SMatthew G. Knepley     }
78357c927364SMatthew G. Knepley   }
78367c927364SMatthew G. Knepley   numCPoints = q;
78377c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
78387c927364SMatthew G. Knepley     PetscInt fdof;
78397c927364SMatthew G. Knepley 
78409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
78417c927364SMatthew G. Knepley     if (!dof) continue;
78427c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
78439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
78447c927364SMatthew G. Knepley       coffsets[f+1] += fdof;
78457c927364SMatthew G. Knepley     }
78467c927364SMatthew G. Knepley     numCIndices += dof;
78477c927364SMatthew G. Knepley   }
78487c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
78497c927364SMatthew G. Knepley   /* Row indices */
78509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
7851412e9a14SMatthew G. Knepley   {
7852012bc364SMatthew G. Knepley     DMPlexTransform tr;
7853012bc364SMatthew G. Knepley     DMPolytopeType *rct;
7854012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
7855012bc364SMatthew G. Knepley 
78569566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
78579566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
78589566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
7859012bc364SMatthew G. Knepley     numSubcells = rsize[Nt-1];
78609566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
7861412e9a14SMatthew G. Knepley   }
78629566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints));
78637c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
78647c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
78659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
78667c927364SMatthew G. Knepley     /* Compress out points not in the section */
78679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
78687c927364SMatthew G. Knepley     for (p = 0; p < numFPoints*2; p += 2) {
78697c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
78709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
78717c927364SMatthew G. Knepley         if (!dof) continue;
78727c927364SMatthew G. Knepley         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
78737c927364SMatthew G. Knepley         if (s < q) continue;
78747c927364SMatthew G. Knepley         ftotpoints[q*2]   = fpoints[p];
78757c927364SMatthew G. Knepley         ftotpoints[q*2+1] = fpoints[p+1];
78767c927364SMatthew G. Knepley         ++q;
78777c927364SMatthew G. Knepley       }
78787c927364SMatthew G. Knepley     }
78799566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
78807c927364SMatthew G. Knepley   }
78817c927364SMatthew G. Knepley   numFPoints = q;
78827c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
78837c927364SMatthew G. Knepley     PetscInt fdof;
78847c927364SMatthew G. Knepley 
78859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
78867c927364SMatthew G. Knepley     if (!dof) continue;
78877c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
78889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
78897c927364SMatthew G. Knepley       foffsets[f+1] += fdof;
78907c927364SMatthew G. Knepley     }
78917c927364SMatthew G. Knepley     numFIndices += dof;
78927c927364SMatthew G. Knepley   }
78937c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
78947c927364SMatthew G. Knepley 
78951dca8a05SBarry 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);
78961dca8a05SBarry 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);
78977c927364SMatthew G. Knepley   if (numFields) {
78984acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
78994acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
79004acb8e1eSToby Isaac 
79014acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
79029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
79039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
79047c927364SMatthew G. Knepley     }
79054acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
79069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
79079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
79084acb8e1eSToby Isaac     }
79094acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
79109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
79119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
79124acb8e1eSToby Isaac     }
79134acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
79149566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL));
79159566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL));
79167c927364SMatthew G. Knepley     }
79177c927364SMatthew G. Knepley   } else {
79184acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
79194acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
79204acb8e1eSToby Isaac 
79219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
79229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL));
79234acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
79244acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
79254acb8e1eSToby Isaac 
79269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff));
79279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
79287c927364SMatthew G. Knepley     }
79294acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
79304acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
79314acb8e1eSToby Isaac 
79329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff));
79339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
79347c927364SMatthew G. Knepley     }
79359566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL));
79369566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL));
79377c927364SMatthew G. Knepley   }
79389566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints));
79399566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
79407c927364SMatthew G. Knepley   PetscFunctionReturn(0);
79417c927364SMatthew G. Knepley }
79427c927364SMatthew G. Knepley 
79437cd05799SMatthew G. Knepley /*@C
79447cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
79457cd05799SMatthew G. Knepley 
79467cd05799SMatthew G. Knepley   Input Parameter:
79477cd05799SMatthew G. Knepley . dm   - The DMPlex object
79487cd05799SMatthew G. Knepley 
79497cd05799SMatthew G. Knepley   Output Parameter:
79507cd05799SMatthew G. Knepley . cellHeight - The height of a cell
79517cd05799SMatthew G. Knepley 
79527cd05799SMatthew G. Knepley   Level: developer
79537cd05799SMatthew G. Knepley 
7954db781477SPatrick Sanan .seealso `DMPlexSetVTKCellHeight()`
79557cd05799SMatthew G. Knepley @*/
7956552f7358SJed Brown PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7957552f7358SJed Brown {
7958552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
7959552f7358SJed Brown 
7960552f7358SJed Brown   PetscFunctionBegin;
7961552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7962dadcf809SJacob Faibussowitsch   PetscValidIntPointer(cellHeight, 2);
7963552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
7964552f7358SJed Brown   PetscFunctionReturn(0);
7965552f7358SJed Brown }
7966552f7358SJed Brown 
79677cd05799SMatthew G. Knepley /*@C
79687cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
79697cd05799SMatthew G. Knepley 
79707cd05799SMatthew G. Knepley   Input Parameters:
79717cd05799SMatthew G. Knepley + dm   - The DMPlex object
79727cd05799SMatthew G. Knepley - cellHeight - The height of a cell
79737cd05799SMatthew G. Knepley 
79747cd05799SMatthew G. Knepley   Level: developer
79757cd05799SMatthew G. Knepley 
7976db781477SPatrick Sanan .seealso `DMPlexGetVTKCellHeight()`
79777cd05799SMatthew G. Knepley @*/
7978552f7358SJed Brown PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7979552f7358SJed Brown {
7980552f7358SJed Brown   DM_Plex *mesh = (DM_Plex*) dm->data;
7981552f7358SJed Brown 
7982552f7358SJed Brown   PetscFunctionBegin;
7983552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7984552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
7985552f7358SJed Brown   PetscFunctionReturn(0);
7986552f7358SJed Brown }
7987552f7358SJed Brown 
7988e6139122SMatthew G. Knepley /*@
7989e6139122SMatthew G. Knepley   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7990e6139122SMatthew G. Knepley 
7991e6139122SMatthew G. Knepley   Input Parameter:
7992e6139122SMatthew G. Knepley . dm - The DMPlex object
7993e6139122SMatthew G. Knepley 
7994e6139122SMatthew G. Knepley   Output Parameters:
79952a9f31c0SMatthew G. Knepley + gcStart - The first ghost cell, or NULL
79962a9f31c0SMatthew G. Knepley - gcEnd   - The upper bound on ghost cells, or NULL
7997e6139122SMatthew G. Knepley 
79982a9f31c0SMatthew G. Knepley   Level: advanced
7999e6139122SMatthew G. Knepley 
8000db781477SPatrick Sanan .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()`
8001e6139122SMatthew G. Knepley @*/
8002e6139122SMatthew G. Knepley PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
8003e6139122SMatthew G. Knepley {
8004412e9a14SMatthew G. Knepley   DMLabel        ctLabel;
8005e6139122SMatthew G. Knepley 
8006e6139122SMatthew G. Knepley   PetscFunctionBegin;
8007e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
80099566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd));
8010e6139122SMatthew G. Knepley   PetscFunctionReturn(0);
8011e6139122SMatthew G. Knepley }
8012e6139122SMatthew G. Knepley 
80139886b8cfSStefano Zampini PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8014552f7358SJed Brown {
8015552f7358SJed Brown   PetscSection   section, globalSection;
8016552f7358SJed Brown   PetscInt      *numbers, p;
8017552f7358SJed Brown 
8018552f7358SJed Brown   PetscFunctionBegin;
80196c1ef331SVaclav Hapla   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf));
80209566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
80219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8022552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
80239566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section, p, 1));
8024552f7358SJed Brown   }
80259566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
80269566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
80279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8028552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
80299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]));
8030ef48cebcSMatthew G. Knepley     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
8031ef48cebcSMatthew G. Knepley     else                       numbers[p-pStart] += shift;
8032552f7358SJed Brown   }
80339566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8034ef48cebcSMatthew G. Knepley   if (globalSize) {
8035ef48cebcSMatthew G. Knepley     PetscLayout layout;
80369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout));
80379566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
80389566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8039ef48cebcSMatthew G. Knepley   }
80409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
80419566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
8042552f7358SJed Brown   PetscFunctionReturn(0);
8043552f7358SJed Brown }
8044552f7358SJed Brown 
804581ed3555SMatthew G. Knepley PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8046552f7358SJed Brown {
8047412e9a14SMatthew G. Knepley   PetscInt       cellHeight, cStart, cEnd;
8048552f7358SJed Brown 
8049552f7358SJed Brown   PetscFunctionBegin;
80509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
80519566063dSJacob Faibussowitsch   if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
80529566063dSJacob Faibussowitsch   else               PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
80539566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
805481ed3555SMatthew G. Knepley   PetscFunctionReturn(0);
8055552f7358SJed Brown }
805681ed3555SMatthew G. Knepley 
80578dab3259SMatthew G. Knepley /*@
80587cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
80597cd05799SMatthew G. Knepley 
80607cd05799SMatthew G. Knepley   Input Parameter:
80617cd05799SMatthew G. Knepley . dm   - The DMPlex object
80627cd05799SMatthew G. Knepley 
80637cd05799SMatthew G. Knepley   Output Parameter:
80647cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
80657cd05799SMatthew G. Knepley 
80667cd05799SMatthew G. Knepley   Level: developer
80677cd05799SMatthew G. Knepley 
8068db781477SPatrick Sanan .seealso `DMPlexGetVertexNumbering()`
80697cd05799SMatthew G. Knepley @*/
807081ed3555SMatthew G. Knepley PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
807181ed3555SMatthew G. Knepley {
807281ed3555SMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex*) dm->data;
807381ed3555SMatthew G. Knepley 
807481ed3555SMatthew G. Knepley   PetscFunctionBegin;
807581ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80769566063dSJacob Faibussowitsch   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8077552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
8078552f7358SJed Brown   PetscFunctionReturn(0);
8079552f7358SJed Brown }
8080552f7358SJed Brown 
808181ed3555SMatthew G. Knepley PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
808281ed3555SMatthew G. Knepley {
8083412e9a14SMatthew G. Knepley   PetscInt       vStart, vEnd;
808481ed3555SMatthew G. Knepley 
808581ed3555SMatthew G. Knepley   PetscFunctionBegin;
808681ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
80889566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
808981ed3555SMatthew G. Knepley   PetscFunctionReturn(0);
809081ed3555SMatthew G. Knepley }
809181ed3555SMatthew G. Knepley 
80928dab3259SMatthew G. Knepley /*@
80936aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
80947cd05799SMatthew G. Knepley 
80957cd05799SMatthew G. Knepley   Input Parameter:
80967cd05799SMatthew G. Knepley . dm   - The DMPlex object
80977cd05799SMatthew G. Knepley 
80987cd05799SMatthew G. Knepley   Output Parameter:
80997cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
81007cd05799SMatthew G. Knepley 
81017cd05799SMatthew G. Knepley   Level: developer
81027cd05799SMatthew G. Knepley 
8103db781477SPatrick Sanan .seealso `DMPlexGetCellNumbering()`
81047cd05799SMatthew G. Knepley @*/
8105552f7358SJed Brown PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8106552f7358SJed Brown {
8107552f7358SJed Brown   DM_Plex       *mesh = (DM_Plex*) dm->data;
8108552f7358SJed Brown 
8109552f7358SJed Brown   PetscFunctionBegin;
8110552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81119566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8112552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
8113552f7358SJed Brown   PetscFunctionReturn(0);
8114552f7358SJed Brown }
8115552f7358SJed Brown 
81168dab3259SMatthew G. Knepley /*@
81177cd05799SMatthew G. Knepley   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
81187cd05799SMatthew G. Knepley 
81197cd05799SMatthew G. Knepley   Input Parameter:
81207cd05799SMatthew G. Knepley . dm   - The DMPlex object
81217cd05799SMatthew G. Knepley 
81227cd05799SMatthew G. Knepley   Output Parameter:
81237cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
81247cd05799SMatthew G. Knepley 
81257cd05799SMatthew G. Knepley   Level: developer
81267cd05799SMatthew G. Knepley 
8127db781477SPatrick Sanan .seealso `DMPlexGetCellNumbering()`
81287cd05799SMatthew G. Knepley @*/
8129ef48cebcSMatthew G. Knepley PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8130ef48cebcSMatthew G. Knepley {
8131ef48cebcSMatthew G. Knepley   IS             nums[4];
8132862913ffSStefano Zampini   PetscInt       depths[4], gdepths[4], starts[4];
8133ef48cebcSMatthew G. Knepley   PetscInt       depth, d, shift = 0;
8134ef48cebcSMatthew G. Knepley 
8135ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8136ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
81388abc87a0SMichael Lange   /* For unstratified meshes use dim instead of depth */
81399566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
8140862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8141862913ffSStefano Zampini     PetscInt end;
8142862913ffSStefano Zampini 
8143862913ffSStefano Zampini     depths[d] = depth-d;
81449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
8145862913ffSStefano Zampini     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8146862913ffSStefano Zampini   }
81479566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(depth+1, starts, depths));
81481c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm)));
8149862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
81501dca8a05SBarry 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]);
8151862913ffSStefano Zampini   }
8152ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8153ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8154ef48cebcSMatthew G. Knepley 
81559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
81569566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8157ef48cebcSMatthew G. Knepley     shift += gsize;
8158ef48cebcSMatthew G. Knepley   }
81599566063dSJacob Faibussowitsch   PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers));
81609566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
8161ef48cebcSMatthew G. Knepley   PetscFunctionReturn(0);
8162ef48cebcSMatthew G. Knepley }
8163ef48cebcSMatthew G. Knepley 
816408a22f4bSMatthew G. Knepley /*@
816508a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
816608a22f4bSMatthew G. Knepley 
816708a22f4bSMatthew G. Knepley   Input Parameter:
816808a22f4bSMatthew G. Knepley . dm - The DMPlex object
816908a22f4bSMatthew G. Knepley 
817008a22f4bSMatthew G. Knepley   Output Parameter:
817108a22f4bSMatthew G. Knepley . ranks - The rank field
817208a22f4bSMatthew G. Knepley 
817308a22f4bSMatthew G. Knepley   Options Database Keys:
817408a22f4bSMatthew G. Knepley . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
817508a22f4bSMatthew G. Knepley 
817608a22f4bSMatthew G. Knepley   Level: intermediate
817708a22f4bSMatthew G. Knepley 
8178db781477SPatrick Sanan .seealso: `DMView()`
817908a22f4bSMatthew G. Knepley @*/
818008a22f4bSMatthew G. Knepley PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
818108a22f4bSMatthew G. Knepley {
818208a22f4bSMatthew G. Knepley   DM             rdm;
818308a22f4bSMatthew G. Knepley   PetscFE        fe;
818408a22f4bSMatthew G. Knepley   PetscScalar   *r;
818508a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
8186a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
818708a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
8188a55f9a55SMatthew G. Knepley   PetscBool      simplex;
818908a22f4bSMatthew G. Knepley 
819008a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
8191f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8192f95ace6aSMatthew G. Knepley   PetscValidPointer(ranks, 2);
81939566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
81949566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
81959566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
81969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
81979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8198a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
81999566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
82009566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) fe, "rank"));
82019566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe));
82029566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
82039566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
82049566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
82059566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition"));
82069566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
820708a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
820808a22f4bSMatthew G. Knepley     PetscScalar *lr;
820908a22f4bSMatthew G. Knepley 
82109566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
821171f09efeSPierre Jolivet     if (lr) *lr = rank;
821208a22f4bSMatthew G. Knepley   }
82139566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
82149566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
821508a22f4bSMatthew G. Knepley   PetscFunctionReturn(0);
821608a22f4bSMatthew G. Knepley }
821708a22f4bSMatthew G. Knepley 
8218ca8062c8SMatthew G. Knepley /*@
821918e14f0cSMatthew G. Knepley   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
822018e14f0cSMatthew G. Knepley 
822118e14f0cSMatthew G. Knepley   Input Parameters:
822218e14f0cSMatthew G. Knepley + dm    - The DMPlex
822318e14f0cSMatthew G. Knepley - label - The DMLabel
822418e14f0cSMatthew G. Knepley 
822518e14f0cSMatthew G. Knepley   Output Parameter:
822618e14f0cSMatthew G. Knepley . val - The label value field
822718e14f0cSMatthew G. Knepley 
822818e14f0cSMatthew G. Knepley   Options Database Keys:
822918e14f0cSMatthew G. Knepley . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
823018e14f0cSMatthew G. Knepley 
823118e14f0cSMatthew G. Knepley   Level: intermediate
823218e14f0cSMatthew G. Knepley 
8233db781477SPatrick Sanan .seealso: `DMView()`
823418e14f0cSMatthew G. Knepley @*/
823518e14f0cSMatthew G. Knepley PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
823618e14f0cSMatthew G. Knepley {
823718e14f0cSMatthew G. Knepley   DM             rdm;
823818e14f0cSMatthew G. Knepley   PetscFE        fe;
823918e14f0cSMatthew G. Knepley   PetscScalar   *v;
824018e14f0cSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
824118e14f0cSMatthew G. Knepley 
824218e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
824318e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
824418e14f0cSMatthew G. Knepley   PetscValidPointer(label, 2);
824518e14f0cSMatthew G. Knepley   PetscValidPointer(val, 3);
82469566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
82479566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
82489566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
82499566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) fe, "label_value"));
82509566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe));
82519566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
82529566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
82539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
82549566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
82559566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *val, "label_value"));
82569566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*val, &v));
825718e14f0cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
825818e14f0cSMatthew G. Knepley     PetscScalar *lv;
825918e14f0cSMatthew G. Knepley     PetscInt     cval;
826018e14f0cSMatthew G. Knepley 
82619566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv));
82629566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, c, &cval));
826318e14f0cSMatthew G. Knepley     *lv = cval;
826418e14f0cSMatthew G. Knepley   }
82659566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*val, &v));
82669566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
826718e14f0cSMatthew G. Knepley   PetscFunctionReturn(0);
826818e14f0cSMatthew G. Knepley }
826918e14f0cSMatthew G. Knepley 
827018e14f0cSMatthew G. Knepley /*@
8271ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8272ca8062c8SMatthew G. Knepley 
827369916449SMatthew G. Knepley   Input Parameter:
827469916449SMatthew G. Knepley . dm - The DMPlex object
8275ca8062c8SMatthew G. Knepley 
827695eb5ee5SVaclav Hapla   Notes:
827795eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
827895eb5ee5SVaclav Hapla 
827995eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8280ca8062c8SMatthew G. Knepley 
8281ca8062c8SMatthew G. Knepley   Level: developer
8282ca8062c8SMatthew G. Knepley 
8283db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8284ca8062c8SMatthew G. Knepley @*/
8285ca8062c8SMatthew G. Knepley PetscErrorCode DMPlexCheckSymmetry(DM dm)
8286ca8062c8SMatthew G. Knepley {
8287ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
8288ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
8289ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
829057beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
829157beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
8292ca8062c8SMatthew G. Knepley 
8293ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8294ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
82959566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
82969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
82979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
8298ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
82999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8300ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
83019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
83029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
8303ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
830442e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
830542e66dfaSMatthew G. Knepley       PetscInt  d;
830642e66dfaSMatthew G. Knepley       for (d = c-1; d >= 0; --d) {
830742e66dfaSMatthew G. Knepley         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
830842e66dfaSMatthew G. Knepley       }
83099566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
83109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
8311ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
8312ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
8313ca8062c8SMatthew G. Knepley       }
831442e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
831563a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
8316ca8062c8SMatthew G. Knepley         for (s = 0; s < coneSize; ++s) {
831763a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
8318ca8062c8SMatthew G. Knepley         }
83199566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
832063a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
8321ca8062c8SMatthew G. Knepley         for (s = 0; s < supportSize; ++s) {
832263a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
8323ca8062c8SMatthew G. Knepley         }
83249566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
832563a3b9bcSJacob 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]);
832663a3b9bcSJacob Faibussowitsch         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
8327ca8062c8SMatthew G. Knepley       }
832842e66dfaSMatthew G. Knepley     }
83299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
833057beb4faSStefano Zampini     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
83319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
83329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
8333ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
83349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
83359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
8336ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
83379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
833857beb4faSStefano Zampini         if (cone[c] != pp) { c = 0; break; }
8339ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
8340ca8062c8SMatthew G. Knepley       }
8341ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
834263a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
8343ca8062c8SMatthew G. Knepley         for (c = 0; c < supportSize; ++c) {
834463a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
8345ca8062c8SMatthew G. Knepley         }
83469566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
834763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
8348ca8062c8SMatthew G. Knepley         for (c = 0; c < coneSize; ++c) {
834963a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
8350ca8062c8SMatthew G. Knepley         }
83519566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
835263a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
8353ca8062c8SMatthew G. Knepley       }
8354ca8062c8SMatthew G. Knepley     }
8355ca8062c8SMatthew G. Knepley   }
835657beb4faSStefano Zampini   if (storagecheck) {
83579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
83589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
835963a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
836057beb4faSStefano Zampini   }
8361ca8062c8SMatthew G. Knepley   PetscFunctionReturn(0);
8362ca8062c8SMatthew G. Knepley }
8363ca8062c8SMatthew G. Knepley 
8364412e9a14SMatthew G. Knepley /*
8365412e9a14SMatthew 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.
8366412e9a14SMatthew G. Knepley */
8367412e9a14SMatthew G. Knepley static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8368412e9a14SMatthew G. Knepley {
8369412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
8370412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
8371412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
8372412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8373412e9a14SMatthew G. Knepley 
8374412e9a14SMatthew G. Knepley   PetscFunctionBegin;
8375412e9a14SMatthew G. Knepley   *unsplit = 0;
8376412e9a14SMatthew G. Knepley   switch (ct) {
8377b5a892a1SMatthew G. Knepley     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8378b5a892a1SMatthew G. Knepley       ptpoints[npt++] = c;
8379b5a892a1SMatthew G. Knepley       break;
8380412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
83819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
83829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
8383412e9a14SMatthew G. Knepley       for (cp = 0; cp < coneSize; ++cp) {
83849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
8385412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8386412e9a14SMatthew G. Knepley       }
8387412e9a14SMatthew G. Knepley       break;
8388412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8389412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_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(DMPlexGetCone(dm, cone[cp], &ccone));
83949566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
8395412e9a14SMatthew G. Knepley         for (ccp = 0; ccp < cconeSize; ++ccp) {
83969566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
8397412e9a14SMatthew G. Knepley           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8398412e9a14SMatthew G. Knepley             PetscInt p;
8399412e9a14SMatthew G. Knepley             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8400412e9a14SMatthew G. Knepley             if (p == npt) ptpoints[npt++] = ccone[ccp];
8401412e9a14SMatthew G. Knepley           }
8402412e9a14SMatthew G. Knepley         }
8403412e9a14SMatthew G. Knepley       }
8404412e9a14SMatthew G. Knepley       break;
8405412e9a14SMatthew G. Knepley     default: break;
8406412e9a14SMatthew G. Knepley   }
8407412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
84089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
8409412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8410412e9a14SMatthew G. Knepley   }
8411412e9a14SMatthew G. Knepley   PetscFunctionReturn(0);
8412412e9a14SMatthew G. Knepley }
8413412e9a14SMatthew G. Knepley 
8414ca8062c8SMatthew G. Knepley /*@
8415ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8416ca8062c8SMatthew G. Knepley 
8417ca8062c8SMatthew G. Knepley   Input Parameters:
8418ca8062c8SMatthew G. Knepley + dm - The DMPlex object
841958723a97SMatthew G. Knepley - cellHeight - Normally 0
8420ca8062c8SMatthew G. Knepley 
842195eb5ee5SVaclav Hapla   Notes:
842295eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
842325c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
8424ca8062c8SMatthew G. Knepley 
842595eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
842695eb5ee5SVaclav Hapla 
8427ca8062c8SMatthew G. Knepley   Level: developer
8428ca8062c8SMatthew G. Knepley 
8429db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8430ca8062c8SMatthew G. Knepley @*/
843125c50c26SVaclav Hapla PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8432ca8062c8SMatthew G. Knepley {
8433412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
8434412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
8435412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
8436ca8062c8SMatthew G. Knepley 
8437ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8438ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84399566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
84409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
84419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8442412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8443412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
8444412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
844558723a97SMatthew G. Knepley 
84469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
844763a3b9bcSJacob Faibussowitsch     PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c);
8448412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8449412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
84509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
845163a3b9bcSJacob 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));
8452412e9a14SMatthew G. Knepley     }
84539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
845458723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
845558723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
8456412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
845758723a97SMatthew G. Knepley     }
84589566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8459412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
8460412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8461412e9a14SMatthew G. Knepley       PetscInt unsplit;
846242363296SMatthew G. Knepley 
84639566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8464412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
846542363296SMatthew G. Knepley     }
846663a3b9bcSJacob 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));
846742363296SMatthew G. Knepley   }
8468ca8062c8SMatthew G. Knepley   PetscFunctionReturn(0);
8469ca8062c8SMatthew G. Knepley }
84709bf0dad6SMatthew G. Knepley 
84719bf0dad6SMatthew G. Knepley /*@
84729bf0dad6SMatthew 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
84739bf0dad6SMatthew G. Knepley 
84748f6815adSVaclav Hapla   Collective
8475899ea2b8SJacob Faibussowitsch 
84769bf0dad6SMatthew G. Knepley   Input Parameters:
84779bf0dad6SMatthew G. Knepley + dm - The DMPlex object
84789bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
84799bf0dad6SMatthew G. Knepley 
848045da879fSVaclav Hapla   Notes:
848145da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
848245da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
848345da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
848445da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
84859bf0dad6SMatthew G. Knepley 
848695eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
848795eb5ee5SVaclav Hapla 
84889bf0dad6SMatthew G. Knepley   Level: developer
84899bf0dad6SMatthew G. Knepley 
8490db781477SPatrick Sanan .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
84919bf0dad6SMatthew G. Knepley @*/
849225c50c26SVaclav Hapla PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
84939bf0dad6SMatthew G. Knepley {
8494ab91121cSMatthew G. Knepley   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8495899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
84969bf0dad6SMatthew G. Knepley 
84979bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
84989bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84998f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
850045da879fSVaclav Hapla   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
85018f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
85028f6815adSVaclav Hapla     PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported");
85038f6815adSVaclav Hapla     PetscFunctionReturn(0);
8504899ea2b8SJacob Faibussowitsch   }
8505899ea2b8SJacob Faibussowitsch 
85069566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
85079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
85089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
8509ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
85109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
85113554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
8512412e9a14SMatthew G. Knepley       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8513412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
8514ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
8515412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
8516412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
85179bf0dad6SMatthew G. Knepley 
85189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
85199566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8520412e9a14SMatthew G. Knepley       if (unsplit) continue;
85219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
85229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
85239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
85249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
85259bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize*2; cl += 2) {
85269bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
85279bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
85289bf0dad6SMatthew G. Knepley       }
85299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
853063a3b9bcSJacob 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);
85319bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
8532d4961f80SStefano Zampini         DMPolytopeType fct;
85339bf0dad6SMatthew G. Knepley         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
85349bf0dad6SMatthew G. Knepley 
85359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
85369566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
85379bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize*2; cl += 2) {
85389bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
85399bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
85409bf0dad6SMatthew G. Knepley         }
854163a3b9bcSJacob 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]);
85429bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
8543b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff+v]) {
8544b5a892a1SMatthew G. Knepley             PetscInt v1;
8545b5a892a1SMatthew G. Knepley 
85469566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
854763a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
85489566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
854963a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1]));
85509566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
855163a3b9bcSJacob 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]);
8552b5a892a1SMatthew G. Knepley           }
85539bf0dad6SMatthew G. Knepley         }
85549566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
8555412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
85569bf0dad6SMatthew G. Knepley       }
85579566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
85589566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
85599bf0dad6SMatthew G. Knepley     }
85603554e41dSMatthew G. Knepley   }
8561552f7358SJed Brown   PetscFunctionReturn(0);
8562552f7358SJed Brown }
85633913d7c8SMatthew G. Knepley 
8564bb6a34a8SMatthew G. Knepley /*@
8565bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
8566bb6a34a8SMatthew G. Knepley 
8567bb6a34a8SMatthew G. Knepley   Input Parameter:
8568bb6a34a8SMatthew G. Knepley . dm - The DMPlex object
8569bb6a34a8SMatthew G. Knepley 
857095eb5ee5SVaclav Hapla   Notes:
857195eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
857295eb5ee5SVaclav Hapla 
857395eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8574bb6a34a8SMatthew G. Knepley 
8575bb6a34a8SMatthew G. Knepley   Level: developer
8576bb6a34a8SMatthew G. Knepley 
8577db781477SPatrick Sanan .seealso: `DMCreate()`, `DMSetFromOptions()`
8578bb6a34a8SMatthew G. Knepley @*/
8579bb6a34a8SMatthew G. Knepley PetscErrorCode DMPlexCheckGeometry(DM dm)
8580bb6a34a8SMatthew G. Knepley {
8581a2a9e04cSMatthew G. Knepley   Vec            coordinates;
8582bb6a34a8SMatthew G. Knepley   PetscReal      detJ, J[9], refVol = 1.0;
8583bb6a34a8SMatthew G. Knepley   PetscReal      vol;
8584412e9a14SMatthew G. Knepley   PetscBool      periodic;
858551a74b61SMatthew G. Knepley   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8586bb6a34a8SMatthew G. Knepley 
8587bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
85889566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
85899566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
859051a74b61SMatthew G. Knepley   if (dim != dE) PetscFunctionReturn(0);
85919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
85929566063dSJacob Faibussowitsch   PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL));
8593bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
85949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8595a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
85969566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8597412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
8598412e9a14SMatthew G. Knepley     DMPolytopeType ct;
8599412e9a14SMatthew G. Knepley     PetscInt       unsplit;
8600412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
8601412e9a14SMatthew G. Knepley 
86029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
8603412e9a14SMatthew G. Knepley     switch (ct) {
8604412e9a14SMatthew G. Knepley       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8605412e9a14SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8606412e9a14SMatthew G. Knepley       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8607412e9a14SMatthew G. Knepley         ignoreZeroVol = PETSC_TRUE; break;
8608412e9a14SMatthew G. Knepley       default: break;
8609412e9a14SMatthew G. Knepley     }
8610412e9a14SMatthew G. Knepley     switch (ct) {
8611412e9a14SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM:
8612412e9a14SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8613412e9a14SMatthew G. Knepley       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8614a2a9e04cSMatthew G. Knepley       case DM_POLYTOPE_PYRAMID:
8615412e9a14SMatthew G. Knepley         continue;
8616412e9a14SMatthew G. Knepley       default: break;
8617412e9a14SMatthew G. Knepley     }
86189566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
8619412e9a14SMatthew G. Knepley     if (unsplit) continue;
86209566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
86211dca8a05SBarry 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);
862263a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol)));
8623412e9a14SMatthew G. Knepley     if (depth > 1 && !periodic) {
86249566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
86251dca8a05SBarry 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);
862663a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol));
8627bb6a34a8SMatthew G. Knepley     }
8628bb6a34a8SMatthew G. Knepley   }
8629bb6a34a8SMatthew G. Knepley   PetscFunctionReturn(0);
8630bb6a34a8SMatthew G. Knepley }
8631bb6a34a8SMatthew G. Knepley 
863203da9461SVaclav Hapla /*@
86337726db96SVaclav Hapla   DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex.
86347726db96SVaclav Hapla 
86357726db96SVaclav Hapla   Collective
863603da9461SVaclav Hapla 
863703da9461SVaclav Hapla   Input Parameters:
86387726db96SVaclav Hapla + dm - The DMPlex object
86397726db96SVaclav Hapla - pointSF - The Point SF, or NULL for Point SF attached to DM
864003da9461SVaclav Hapla 
8641e83a0d2dSVaclav Hapla   Notes:
8642e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
864303da9461SVaclav Hapla 
864495eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
864595eb5ee5SVaclav Hapla 
864603da9461SVaclav Hapla   Level: developer
864703da9461SVaclav Hapla 
8648db781477SPatrick Sanan .seealso: `DMGetPointSF()`, `DMSetFromOptions()`
864903da9461SVaclav Hapla @*/
86507726db96SVaclav Hapla PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF)
865103da9461SVaclav Hapla {
86527726db96SVaclav Hapla   PetscInt        l, nleaves, nroots, overlap;
86537726db96SVaclav Hapla   const PetscInt *locals;
86547726db96SVaclav Hapla   const PetscSFNode *remotes;
8655f0cfc026SVaclav Hapla   PetscBool       distributed;
86567726db96SVaclav Hapla   MPI_Comm        comm;
86577726db96SVaclav Hapla   PetscMPIInt     rank;
865803da9461SVaclav Hapla 
865903da9461SVaclav Hapla   PetscFunctionBegin;
866003da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86617726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
86627726db96SVaclav Hapla   else         pointSF = dm->sf;
86637726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
86647726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
86657726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
86667726db96SVaclav Hapla   {
86677726db96SVaclav Hapla     PetscMPIInt    mpiFlag;
86687726db96SVaclav Hapla 
86697726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag));
86707726db96SVaclav 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);
86717726db96SVaclav Hapla   }
86727726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
86739566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
86747726db96SVaclav Hapla   if (!distributed) {
86757726db96SVaclav 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);
86768918e3e2SVaclav Hapla     PetscFunctionReturn(0);
86778918e3e2SVaclav Hapla   }
86787726db96SVaclav 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);
86797726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
868003da9461SVaclav Hapla 
86817726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
86827726db96SVaclav Hapla   {
86837726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
86847726db96SVaclav Hapla 
86857726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
86867726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
86877726db96SVaclav Hapla     PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots);
86887726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
86897726db96SVaclav Hapla   }
86907726db96SVaclav Hapla 
86917726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
86927726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
86937726db96SVaclav 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);
86947726db96SVaclav Hapla   }
86957726db96SVaclav Hapla 
86967726db96SVaclav Hapla   /* Check there are no cells in interface */
86977726db96SVaclav Hapla   if (!overlap) {
86987726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
86997726db96SVaclav Hapla 
87009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
87019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
8702f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
87037726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
8704f5869d18SMatthew G. Knepley 
87057726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
87067726db96SVaclav Hapla     }
870703da9461SVaclav Hapla   }
8708ece87651SVaclav Hapla 
87097726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
87107726db96SVaclav Hapla   {
87117726db96SVaclav Hapla     const PetscInt *rootdegree;
87127726db96SVaclav Hapla 
87137726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
87147726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
8715f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
87167726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
8717f5869d18SMatthew G. Knepley       const PetscInt *cone;
8718f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
8719f5869d18SMatthew G. Knepley 
87209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
87219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
8722f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
8723f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
87247726db96SVaclav Hapla           if (locals) {
87259566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
87267726db96SVaclav Hapla           } else {
87277726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
87287726db96SVaclav Hapla           }
872963a3b9bcSJacob 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]);
8730f5869d18SMatthew G. Knepley         }
8731f5869d18SMatthew G. Knepley       }
8732ece87651SVaclav Hapla     }
87337726db96SVaclav Hapla   }
873403da9461SVaclav Hapla   PetscFunctionReturn(0);
873503da9461SVaclav Hapla }
873603da9461SVaclav Hapla 
87377f9d8d6cSVaclav Hapla /*@
87387f9d8d6cSVaclav Hapla   DMPlexCheck - Perform various checks of Plex sanity
87397f9d8d6cSVaclav Hapla 
87407f9d8d6cSVaclav Hapla   Input Parameter:
87417f9d8d6cSVaclav Hapla . dm - The DMPlex object
87427f9d8d6cSVaclav Hapla 
87437f9d8d6cSVaclav Hapla   Notes:
87447f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
87457f9d8d6cSVaclav Hapla 
87467f9d8d6cSVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
87477f9d8d6cSVaclav Hapla 
87487f9d8d6cSVaclav Hapla   Currently does not include DMPlexCheckCellShape().
87497f9d8d6cSVaclav Hapla 
87507f9d8d6cSVaclav Hapla   Level: developer
87517f9d8d6cSVaclav Hapla 
87527f9d8d6cSVaclav Hapla .seealso: DMCreate(), DMSetFromOptions()
87537f9d8d6cSVaclav Hapla @*/
87547f9d8d6cSVaclav Hapla PetscErrorCode DMPlexCheck(DM dm)
8755b5a892a1SMatthew G. Knepley {
87567f9d8d6cSVaclav Hapla   PetscInt cellHeight;
87577f9d8d6cSVaclav Hapla 
8758b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
87597f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
87609566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
87619566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
87629566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
87639566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
87647726db96SVaclav Hapla   PetscCall(DMPlexCheckPointSF(dm, NULL));
87659566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
8766b5a892a1SMatthew G. Knepley   PetscFunctionReturn(0);
8767b5a892a1SMatthew G. Knepley }
8768b5a892a1SMatthew G. Knepley 
8769068a5610SStefano Zampini typedef struct cell_stats
8770068a5610SStefano Zampini {
8771068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
8772068a5610SStefano Zampini   PetscInt  count;
8773068a5610SStefano Zampini } cell_stats_t;
8774068a5610SStefano Zampini 
877525befc3bSSatish Balay static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8776068a5610SStefano Zampini {
8777068a5610SStefano Zampini   PetscInt i, N = *len;
8778068a5610SStefano Zampini 
8779068a5610SStefano Zampini   for (i = 0; i < N; i++) {
8780068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *) a;
8781068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *) b;
8782068a5610SStefano Zampini 
8783068a5610SStefano Zampini     B->min = PetscMin(A->min,B->min);
8784068a5610SStefano Zampini     B->max = PetscMax(A->max,B->max);
8785068a5610SStefano Zampini     B->sum += A->sum;
8786068a5610SStefano Zampini     B->squaresum += A->squaresum;
8787068a5610SStefano Zampini     B->count += A->count;
8788068a5610SStefano Zampini   }
8789068a5610SStefano Zampini }
8790068a5610SStefano Zampini 
8791068a5610SStefano Zampini /*@
879243fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8793068a5610SStefano Zampini 
87948261a58bSMatthew G. Knepley   Collective on dm
87958261a58bSMatthew G. Knepley 
8796068a5610SStefano Zampini   Input Parameters:
8797068a5610SStefano Zampini + dm        - The DMPlex object
879843fa8764SMatthew G. Knepley . output    - If true, statistics will be displayed on stdout
879943fa8764SMatthew G. Knepley - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8800068a5610SStefano Zampini 
880195eb5ee5SVaclav Hapla   Notes:
880295eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
880395eb5ee5SVaclav Hapla 
880495eb5ee5SVaclav Hapla   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8805068a5610SStefano Zampini 
8806068a5610SStefano Zampini   Level: developer
8807068a5610SStefano Zampini 
8808db781477SPatrick Sanan .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
8809068a5610SStefano Zampini @*/
881043fa8764SMatthew G. Knepley PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8811068a5610SStefano Zampini {
8812068a5610SStefano Zampini   DM             dmCoarse;
881343fa8764SMatthew G. Knepley   cell_stats_t   stats, globalStats;
881443fa8764SMatthew G. Knepley   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
881543fa8764SMatthew G. Knepley   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
881643fa8764SMatthew G. Knepley   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8817412e9a14SMatthew G. Knepley   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
881843fa8764SMatthew G. Knepley   PetscMPIInt    rank,size;
8819068a5610SStefano Zampini 
8820068a5610SStefano Zampini   PetscFunctionBegin;
8821068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8822068a5610SStefano Zampini   stats.min   = PETSC_MAX_REAL;
8823068a5610SStefano Zampini   stats.max   = PETSC_MIN_REAL;
8824068a5610SStefano Zampini   stats.sum   = stats.squaresum = 0.;
8825068a5610SStefano Zampini   stats.count = 0;
8826068a5610SStefano Zampini 
88279566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
88289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
88299566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm,&cdim));
88309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
88319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
88329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd));
8833412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
8834068a5610SStefano Zampini     PetscInt  i;
8835068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8836068a5610SStefano Zampini 
88379566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ));
883863a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
883943fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
8840068a5610SStefano Zampini       frobJ    += J[i] * J[i];
8841068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
8842068a5610SStefano Zampini     }
8843068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
8844068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
8845068a5610SStefano Zampini 
8846068a5610SStefano Zampini     stats.min        = PetscMin(stats.min,cond);
8847068a5610SStefano Zampini     stats.max        = PetscMax(stats.max,cond);
8848068a5610SStefano Zampini     stats.sum       += cond;
8849068a5610SStefano Zampini     stats.squaresum += cond2;
8850068a5610SStefano Zampini     stats.count++;
88518261a58bSMatthew G. Knepley     if (output && cond > limit) {
885243fa8764SMatthew G. Knepley       PetscSection coordSection;
885343fa8764SMatthew G. Knepley       Vec          coordsLocal;
885443fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
885543fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
885643fa8764SMatthew G. Knepley 
88579566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
88589566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
88599566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
886063a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond));
886143fa8764SMatthew G. Knepley       for (i = 0; i < Nv/cdim; ++i) {
886263a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
886343fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
88649566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
88659566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d])));
886643fa8764SMatthew G. Knepley         }
88679566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
886843fa8764SMatthew G. Knepley       }
88699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
887043fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize*2; cl += 2) {
887143fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
887243fa8764SMatthew G. Knepley 
887343fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
887443fa8764SMatthew G. Knepley           PetscReal len;
887543fa8764SMatthew G. Knepley 
88769566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
887763a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double) len));
887843fa8764SMatthew G. Knepley         }
887943fa8764SMatthew G. Knepley       }
88809566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
88819566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
888243fa8764SMatthew G. Knepley     }
8883068a5610SStefano Zampini   }
88849566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
8885068a5610SStefano Zampini 
8886068a5610SStefano Zampini   if (size > 1) {
8887068a5610SStefano Zampini     PetscMPIInt   blockLengths[2] = {4,1};
8888068a5610SStefano Zampini     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8889068a5610SStefano Zampini     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8890068a5610SStefano Zampini     MPI_Op        statReduce;
8891068a5610SStefano Zampini 
88929566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType));
88939566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
88949566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
88959566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm));
88969566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
88979566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
8898068a5610SStefano Zampini   } else {
88999566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats,&stats,1));
8900068a5610SStefano Zampini   }
8901dd400576SPatrick Sanan   if (rank == 0) {
8902068a5610SStefano Zampini     count = globalStats.count;
8903068a5610SStefano Zampini     min   = globalStats.min;
8904068a5610SStefano Zampini     max   = globalStats.max;
8905068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
8906068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8907068a5610SStefano Zampini   }
8908068a5610SStefano Zampini 
8909068a5610SStefano Zampini   if (output) {
891063a3b9bcSJacob 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));
8911068a5610SStefano Zampini   }
89129566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J,invJ));
8913068a5610SStefano Zampini 
89149566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm,&dmCoarse));
8915068a5610SStefano Zampini   if (dmCoarse) {
8916068a5610SStefano Zampini     PetscBool isplex;
8917068a5610SStefano Zampini 
89189566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex));
8919068a5610SStefano Zampini     if (isplex) {
89209566063dSJacob Faibussowitsch       PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit));
8921068a5610SStefano Zampini     }
8922068a5610SStefano Zampini   }
8923068a5610SStefano Zampini   PetscFunctionReturn(0);
8924068a5610SStefano Zampini }
8925068a5610SStefano Zampini 
8926f108dbd7SJacob Faibussowitsch /*@
8927f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8928f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
8929f108dbd7SJacob Faibussowitsch 
89306ed19f2fSJacob Faibussowitsch   Collective on dm
8931f108dbd7SJacob Faibussowitsch 
8932f108dbd7SJacob Faibussowitsch   Input Parameters:
8933f108dbd7SJacob Faibussowitsch + dm   - The DMPlex object
8934f108dbd7SJacob Faibussowitsch . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8935f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
8936f108dbd7SJacob Faibussowitsch 
8937f108dbd7SJacob Faibussowitsch   Output Parameters:
8938f108dbd7SJacob Faibussowitsch + OrthQual      - Vec containing orthogonal quality per cell
8939f108dbd7SJacob Faibussowitsch - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8940f108dbd7SJacob Faibussowitsch 
8941f108dbd7SJacob Faibussowitsch   Options Database Keys:
8942f108dbd7SJacob Faibussowitsch + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8943f108dbd7SJacob Faibussowitsch supported.
8944f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8945f108dbd7SJacob Faibussowitsch 
8946f108dbd7SJacob Faibussowitsch   Notes:
8947f108dbd7SJacob Faibussowitsch   Orthogonal quality is given by the following formula:
8948f108dbd7SJacob Faibussowitsch 
8949f108dbd7SJacob Faibussowitsch   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8950f108dbd7SJacob Faibussowitsch 
8951f108dbd7SJacob 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
8952f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8953f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8954f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
8955f108dbd7SJacob Faibussowitsch 
8956f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
8957f108dbd7SJacob Faibussowitsch 
8958f108dbd7SJacob Faibussowitsch   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8959f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8960f108dbd7SJacob Faibussowitsch 
8961f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8962f108dbd7SJacob Faibussowitsch 
8963f108dbd7SJacob Faibussowitsch   Level: intermediate
8964f108dbd7SJacob Faibussowitsch 
8965db781477SPatrick Sanan .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()`
8966f108dbd7SJacob Faibussowitsch @*/
8967f108dbd7SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8968f108dbd7SJacob Faibussowitsch {
89696ed19f2fSJacob Faibussowitsch   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
89706ed19f2fSJacob Faibussowitsch   PetscInt                *idx;
89716ed19f2fSJacob Faibussowitsch   PetscScalar             *oqVals;
8972f108dbd7SJacob Faibussowitsch   const PetscScalar       *cellGeomArr, *faceGeomArr;
89736ed19f2fSJacob Faibussowitsch   PetscReal               *ci, *fi, *Ai;
8974f108dbd7SJacob Faibussowitsch   MPI_Comm                comm;
8975f108dbd7SJacob Faibussowitsch   Vec                     cellgeom, facegeom;
8976f108dbd7SJacob Faibussowitsch   DM                      dmFace, dmCell;
8977f108dbd7SJacob Faibussowitsch   IS                      glob;
8978f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping  ltog;
8979f108dbd7SJacob Faibussowitsch   PetscViewer             vwr;
8980f108dbd7SJacob Faibussowitsch 
8981f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
8982f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89836ed19f2fSJacob Faibussowitsch   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8984f108dbd7SJacob Faibussowitsch   PetscValidPointer(OrthQual, 4);
89856bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol);
89869566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
89879566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
898863a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
89896ed19f2fSJacob Faibussowitsch   {
89906ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
89916ed19f2fSJacob Faibussowitsch 
89929566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
8993f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8994f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
8995f108dbd7SJacob Faibussowitsch 
89969566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
899798921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8998f108dbd7SJacob Faibussowitsch     }
89996ed19f2fSJacob Faibussowitsch   }
9000f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
9001f108dbd7SJacob Faibussowitsch     PetscValidPointer(OrthQualLabel, 5);
90029566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
90039566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
90046ed19f2fSJacob Faibussowitsch   } else {*OrthQualLabel = NULL;}
90059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
90069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
90079566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
90089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
90099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
90109566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
90119566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
90129566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE));
90139566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
90149566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
90159566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
90169566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
90179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
90189566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
90199566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
90209566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
90219566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
90229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
90236ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
90246ed19f2fSJacob Faibussowitsch     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9025f108dbd7SJacob Faibussowitsch     PetscInt           cellarr[2], *adj = NULL;
9026f108dbd7SJacob Faibussowitsch     PetscScalar        *cArr, *fArr;
9027898cd552SSatish Balay     PetscReal          minvalc = 1.0, minvalf = 1.0;
9028f108dbd7SJacob Faibussowitsch     PetscFVCellGeom    *cg;
9029f108dbd7SJacob Faibussowitsch 
90306ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell-cStart;
9031f108dbd7SJacob Faibussowitsch     cellarr[0] = cell;
9032f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
90339566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
90349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9035f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
90369566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
90376ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
90386ed19f2fSJacob Faibussowitsch       PetscInt         i;
90396ed19f2fSJacob Faibussowitsch       const PetscInt   neigh = adj[cellneigh];
9040f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9041f108dbd7SJacob Faibussowitsch       PetscFVCellGeom  *cgneigh;
9042f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom  *fg;
9043f108dbd7SJacob Faibussowitsch 
9044f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9045f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
90469566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9047f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
90486ed19f2fSJacob Faibussowitsch       {
90496ed19f2fSJacob Faibussowitsch         PetscInt       numcovpts;
90506ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
90516ed19f2fSJacob Faibussowitsch 
90529566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
90539566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
90549566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
90556ed19f2fSJacob Faibussowitsch       }
9056f108dbd7SJacob Faibussowitsch 
9057f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9058f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9059f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9060f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9061f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9062addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9063addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9064addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9065f108dbd7SJacob Faibussowitsch       }
9066addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9067addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9068addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9069f108dbd7SJacob Faibussowitsch 
9070f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9071f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9072f108dbd7SJacob Faibussowitsch         ci[i] = ci[i]/normci;
9073f108dbd7SJacob Faibussowitsch         fi[i] = fi[i]/normfi;
9074f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i]/normai;
9075f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9076f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
9077f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
9078f108dbd7SJacob Faibussowitsch       }
9079f108dbd7SJacob Faibussowitsch       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
9080f108dbd7SJacob Faibussowitsch         minvalc = PetscRealPart(cArr[cellneighiter]);
9081f108dbd7SJacob Faibussowitsch       }
9082f108dbd7SJacob Faibussowitsch       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
9083f108dbd7SJacob Faibussowitsch         minvalf = PetscRealPart(fArr[cellneighiter]);
9084f108dbd7SJacob Faibussowitsch       }
9085f108dbd7SJacob Faibussowitsch     }
90869566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
90879566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9088f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
90896ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9090f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
90919566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9092f108dbd7SJacob Faibussowitsch     }
9093f108dbd7SJacob Faibussowitsch   }
90949566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES));
90959566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
90969566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
90979566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
90989566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
90999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9100f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
91019566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9102f108dbd7SJacob Faibussowitsch   }
91039566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
91049566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&vwr));
91059566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
9106f108dbd7SJacob Faibussowitsch   PetscFunctionReturn(0);
9107f108dbd7SJacob Faibussowitsch }
9108f108dbd7SJacob Faibussowitsch 
91091eb70e55SToby Isaac /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
91101eb70e55SToby Isaac  * interpolator construction */
91111eb70e55SToby Isaac static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
91121eb70e55SToby Isaac {
91131eb70e55SToby Isaac   PetscSection   section, newSection, gsection;
91141eb70e55SToby Isaac   PetscSF        sf;
91151eb70e55SToby Isaac   PetscBool      hasConstraints, ghasConstraints;
91161eb70e55SToby Isaac 
91171eb70e55SToby Isaac   PetscFunctionBegin;
91181eb70e55SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
91191eb70e55SToby Isaac   PetscValidPointer(odm,2);
91209566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
91219566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
91229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm)));
91231eb70e55SToby Isaac   if (!ghasConstraints) {
91249566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
91251eb70e55SToby Isaac     *odm = dm;
91261eb70e55SToby Isaac     PetscFunctionReturn(0);
91271eb70e55SToby Isaac   }
91289566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
91299566063dSJacob Faibussowitsch   PetscCall(DMCopyFields(dm, *odm));
91309566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
91319566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
91329566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
91339566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
91349566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
91351eb70e55SToby Isaac   PetscFunctionReturn(0);
91361eb70e55SToby Isaac }
91371eb70e55SToby Isaac 
91381eb70e55SToby Isaac static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
91391eb70e55SToby Isaac {
91401eb70e55SToby Isaac   DM             dmco, dmfo;
91411eb70e55SToby Isaac   Mat            interpo;
91421eb70e55SToby Isaac   Vec            rscale;
91431eb70e55SToby Isaac   Vec            cglobalo, clocal;
91441eb70e55SToby Isaac   Vec            fglobal, fglobalo, flocal;
91451eb70e55SToby Isaac   PetscBool      regular;
91461eb70e55SToby Isaac 
91471eb70e55SToby Isaac   PetscFunctionBegin;
91489566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
91499566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
91509566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
91519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
91529566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
91539566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
91549566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
91559566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
91569566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
91579566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
91589566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
91599566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
91609566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
91619566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
91629566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
91639566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
91649566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
91659566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
91669566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
91679566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
91689566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
91699566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
91709566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
91719566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
91721eb70e55SToby Isaac   *shift = fglobal;
91739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
91749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
91759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
91769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
91779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
91789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
91799566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
91809566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
91811eb70e55SToby Isaac   PetscFunctionReturn(0);
91821eb70e55SToby Isaac }
91831eb70e55SToby Isaac 
91841eb70e55SToby Isaac PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
91851eb70e55SToby Isaac {
91861eb70e55SToby Isaac   PetscObject    shifto;
91871eb70e55SToby Isaac   Vec            shift;
91881eb70e55SToby Isaac 
91891eb70e55SToby Isaac   PetscFunctionBegin;
91901eb70e55SToby Isaac   if (!interp) {
91911eb70e55SToby Isaac     Vec rscale;
91921eb70e55SToby Isaac 
91939566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
91949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
91951eb70e55SToby Isaac   } else {
91969566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
91971eb70e55SToby Isaac   }
91989566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
91991eb70e55SToby Isaac   if (!shifto) {
92009566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
92019566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift));
92021eb70e55SToby Isaac     shifto = (PetscObject) shift;
92039566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
92041eb70e55SToby Isaac   }
92051eb70e55SToby Isaac   shift = (Vec) shifto;
92069566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
92079566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
92089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
92091eb70e55SToby Isaac   PetscFunctionReturn(0);
92101eb70e55SToby Isaac }
92111eb70e55SToby Isaac 
9212bceba477SMatthew G. Knepley /* Pointwise interpolation
9213bceba477SMatthew G. Knepley      Just code FEM for now
9214bceba477SMatthew G. Knepley      u^f = I u^c
92154ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
92164ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
92174ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
9218bceba477SMatthew G. Knepley */
9219bceba477SMatthew G. Knepley PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9220bceba477SMatthew G. Knepley {
9221bceba477SMatthew G. Knepley   PetscSection   gsc, gsf;
9222bceba477SMatthew G. Knepley   PetscInt       m, n;
9223a063dac3SMatthew G. Knepley   void          *ctx;
922468132eb9SMatthew G. Knepley   DM             cdm;
9225cf51de39SMatthew G. Knepley   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9226bceba477SMatthew G. Knepley 
9227bceba477SMatthew G. Knepley   PetscFunctionBegin;
92289566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
92299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
92309566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
92319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
923268132eb9SMatthew G. Knepley 
92339566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
92349566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation));
92359566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
92369566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
92379566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
923868132eb9SMatthew G. Knepley 
92399566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
92409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
92419566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
92429566063dSJacob Faibussowitsch   else                                            PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
92439566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
92444db47ee9SStefano Zampini   if (scaling) {
92455d1c2e58SMatthew G. Knepley     /* Use naive scaling */
92469566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
92474db47ee9SStefano Zampini   }
9248a063dac3SMatthew G. Knepley   PetscFunctionReturn(0);
9249a063dac3SMatthew G. Knepley }
9250bceba477SMatthew G. Knepley 
92516dbf9973SLawrence Mitchell PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9252a063dac3SMatthew G. Knepley {
92536dbf9973SLawrence Mitchell   VecScatter     ctx;
925490748bafSMatthew G. Knepley 
9255a063dac3SMatthew G. Knepley   PetscFunctionBegin;
92569566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
92579566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
92589566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
9259bceba477SMatthew G. Knepley   PetscFunctionReturn(0);
9260bceba477SMatthew G. Knepley }
9261bceba477SMatthew G. Knepley 
92623e9753d6SMatthew G. Knepley static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
92633e9753d6SMatthew G. Knepley                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
92643e9753d6SMatthew G. Knepley                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
92653e9753d6SMatthew G. Knepley                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
92663e9753d6SMatthew G. Knepley {
926700635df3SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
926800635df3SMatthew G. Knepley   PetscInt       c;
926900635df3SMatthew G. Knepley   for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0;
92703e9753d6SMatthew G. Knepley }
92713e9753d6SMatthew G. Knepley 
9272b4937a87SMatthew G. Knepley PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9273b4937a87SMatthew G. Knepley {
9274b4937a87SMatthew G. Knepley   DM             dmc;
9275b4937a87SMatthew G. Knepley   PetscDS        ds;
9276b4937a87SMatthew G. Knepley   Vec            ones, locmass;
9277b4937a87SMatthew G. Knepley   IS             cellIS;
9278b4937a87SMatthew G. Knepley   PetscFormKey   key;
9279b4937a87SMatthew G. Knepley   PetscInt       depth;
9280b4937a87SMatthew G. Knepley 
9281b4937a87SMatthew G. Knepley   PetscFunctionBegin;
92829566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
92839566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
92849566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
92859566063dSJacob Faibussowitsch   PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
92869566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmc, mass));
92879566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &ones));
92889566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &locmass));
92899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmc, &depth));
92909566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
92919566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
92929566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
9293b4937a87SMatthew G. Knepley   key.label = NULL;
9294b4937a87SMatthew G. Knepley   key.value = 0;
9295b4937a87SMatthew G. Knepley   key.field = 0;
9296b4937a87SMatthew G. Knepley   key.part  = 0;
92979566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
92989566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
92999566063dSJacob Faibussowitsch   PetscCall(VecSet(*mass, 0.0));
93009566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
93019566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
93029566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &ones));
93039566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &locmass));
93049566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
9305b4937a87SMatthew G. Knepley   PetscFunctionReturn(0);
9306b4937a87SMatthew G. Knepley }
9307b4937a87SMatthew G. Knepley 
9308bd041c0cSMatthew G. Knepley PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9309bd041c0cSMatthew G. Knepley {
9310bd041c0cSMatthew G. Knepley   PetscSection   gsc, gsf;
9311bd041c0cSMatthew G. Knepley   PetscInt       m, n;
9312bd041c0cSMatthew G. Knepley   void          *ctx;
9313bd041c0cSMatthew G. Knepley   DM             cdm;
9314bd041c0cSMatthew G. Knepley   PetscBool      regular;
9315bd041c0cSMatthew G. Knepley 
9316bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
93173e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
93183e9753d6SMatthew G. Knepley     DM            dmc;
93193e9753d6SMatthew G. Knepley     PetscDS       ds;
9320b4937a87SMatthew G. Knepley     PetscWeakForm wf;
93213e9753d6SMatthew G. Knepley     Vec           u;
93223e9753d6SMatthew G. Knepley     IS            cellIS;
932306ad1575SMatthew G. Knepley     PetscFormKey  key;
93243e9753d6SMatthew G. Knepley     PetscInt      depth;
93253e9753d6SMatthew G. Knepley 
93269566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
93279566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
93289566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
93299566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
93309566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
93319566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
93329566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
93339566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmc, &u));
93349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
93359566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
93369566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
93376528b96dSMatthew G. Knepley     key.label = NULL;
93386528b96dSMatthew G. Knepley     key.value = 0;
93396528b96dSMatthew G. Knepley     key.field = 0;
934006ad1575SMatthew G. Knepley     key.part  = 0;
93419566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
93429566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
93439566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmc, &u));
93449566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
93453e9753d6SMatthew G. Knepley   } else {
93469566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
93479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
93489566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
93499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
9350bd041c0cSMatthew G. Knepley 
93519566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass));
93529566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
93539566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
93549566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
9355bd041c0cSMatthew G. Knepley 
93569566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
93579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
93589566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
93599566063dSJacob Faibussowitsch     else                            PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
93603e9753d6SMatthew G. Knepley   }
93619566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
9362bd041c0cSMatthew G. Knepley   PetscFunctionReturn(0);
9363bd041c0cSMatthew G. Knepley }
9364bd041c0cSMatthew G. Knepley 
93650aef6b92SMatthew G. Knepley /*@
93660aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
93670aef6b92SMatthew G. Knepley 
93680aef6b92SMatthew G. Knepley   Input Parameter:
93690aef6b92SMatthew G. Knepley . dm - The DMPlex object
93700aef6b92SMatthew G. Knepley 
93710aef6b92SMatthew G. Knepley   Output Parameter:
93720aef6b92SMatthew G. Knepley . regular - The flag
93730aef6b92SMatthew G. Knepley 
93740aef6b92SMatthew G. Knepley   Level: intermediate
93750aef6b92SMatthew G. Knepley 
9376db781477SPatrick Sanan .seealso: `DMPlexSetRegularRefinement()`
93770aef6b92SMatthew G. Knepley @*/
93780aef6b92SMatthew G. Knepley PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
93790aef6b92SMatthew G. Knepley {
93800aef6b92SMatthew G. Knepley   PetscFunctionBegin;
93810aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9382dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(regular, 2);
93830aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *) dm->data)->regularRefinement;
93840aef6b92SMatthew G. Knepley   PetscFunctionReturn(0);
93850aef6b92SMatthew G. Knepley }
93860aef6b92SMatthew G. Knepley 
93870aef6b92SMatthew G. Knepley /*@
93880aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
93890aef6b92SMatthew G. Knepley 
93900aef6b92SMatthew G. Knepley   Input Parameters:
93910aef6b92SMatthew G. Knepley + dm - The DMPlex object
93920aef6b92SMatthew G. Knepley - regular - The flag
93930aef6b92SMatthew G. Knepley 
93940aef6b92SMatthew G. Knepley   Level: intermediate
93950aef6b92SMatthew G. Knepley 
9396db781477SPatrick Sanan .seealso: `DMPlexGetRegularRefinement()`
93970aef6b92SMatthew G. Knepley @*/
93980aef6b92SMatthew G. Knepley PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
93990aef6b92SMatthew G. Knepley {
94000aef6b92SMatthew G. Knepley   PetscFunctionBegin;
94010aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
94020aef6b92SMatthew G. Knepley   ((DM_Plex *) dm->data)->regularRefinement = regular;
94030aef6b92SMatthew G. Knepley   PetscFunctionReturn(0);
94040aef6b92SMatthew G. Knepley }
94050aef6b92SMatthew G. Knepley 
9406f7c74593SToby Isaac /* anchors */
9407a68b90caSToby Isaac /*@
9408f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9409ebdb1bfaSJed Brown   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints().
9410a68b90caSToby Isaac 
9411e228b242SToby Isaac   not collective
9412a68b90caSToby Isaac 
9413f899ff85SJose E. Roman   Input Parameter:
9414a68b90caSToby Isaac . dm - The DMPlex object
9415a68b90caSToby Isaac 
9416a68b90caSToby Isaac   Output Parameters:
9417a68b90caSToby Isaac + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9418a68b90caSToby Isaac - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9419a68b90caSToby Isaac 
9420a68b90caSToby Isaac   Level: intermediate
9421a68b90caSToby Isaac 
9422db781477SPatrick Sanan .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9423a68b90caSToby Isaac @*/
9424a17985deSToby Isaac PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9425a68b90caSToby Isaac {
9426a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
9427a68b90caSToby Isaac 
9428a68b90caSToby Isaac   PetscFunctionBegin;
9429a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
94309566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
9431a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
9432a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
9433a68b90caSToby Isaac   PetscFunctionReturn(0);
9434a68b90caSToby Isaac }
9435a68b90caSToby Isaac 
9436a68b90caSToby Isaac /*@
9437f7c74593SToby Isaac   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9438f7c74593SToby Isaac   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9439a68b90caSToby Isaac   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9440a68b90caSToby Isaac 
9441a17985deSToby Isaac   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9442ebdb1bfaSJed Brown   DMGetDefaultConstraints() and filling in the entries in the constraint matrix.
9443a68b90caSToby Isaac 
9444e228b242SToby Isaac   collective on dm
9445a68b90caSToby Isaac 
9446a68b90caSToby Isaac   Input Parameters:
9447a68b90caSToby Isaac + dm - The DMPlex object
9448e228b242SToby 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).
9449e228b242SToby Isaac - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9450a68b90caSToby Isaac 
9451a68b90caSToby Isaac   The reference counts of anchorSection and anchorIS are incremented.
9452a68b90caSToby Isaac 
9453a68b90caSToby Isaac   Level: intermediate
9454a68b90caSToby Isaac 
9455db781477SPatrick Sanan .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
9456a68b90caSToby Isaac @*/
9457a17985deSToby Isaac PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9458a68b90caSToby Isaac {
9459a68b90caSToby Isaac   DM_Plex        *plex = (DM_Plex *)dm->data;
9460e228b242SToby Isaac   PetscMPIInt    result;
9461a68b90caSToby Isaac 
9462a68b90caSToby Isaac   PetscFunctionBegin;
9463a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9464e228b242SToby Isaac   if (anchorSection) {
9465e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
94669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result));
94671dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9468e228b242SToby Isaac   }
9469e228b242SToby Isaac   if (anchorIS) {
9470e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
94719566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result));
94721dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9473e228b242SToby Isaac   }
9474a68b90caSToby Isaac 
94759566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
94769566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
9477a68b90caSToby Isaac   plex->anchorSection = anchorSection;
9478a68b90caSToby Isaac 
94799566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
94809566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
9481a68b90caSToby Isaac   plex->anchorIS = anchorIS;
9482a68b90caSToby Isaac 
9483cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9484a68b90caSToby Isaac     PetscInt size, a, pStart, pEnd;
9485a68b90caSToby Isaac     const PetscInt *anchors;
9486a68b90caSToby Isaac 
94879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd));
94889566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS,&size));
94899566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS,&anchors));
9490a68b90caSToby Isaac     for (a = 0; a < size; a++) {
9491a68b90caSToby Isaac       PetscInt p;
9492a68b90caSToby Isaac 
9493a68b90caSToby Isaac       p = anchors[a];
9494a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
9495a68b90caSToby Isaac         PetscInt dof;
9496a68b90caSToby Isaac 
94979566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection,p,&dof));
9498a68b90caSToby Isaac         if (dof) {
9499a68b90caSToby Isaac 
95009566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS,&anchors));
950163a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p);
9502a68b90caSToby Isaac         }
9503a68b90caSToby Isaac       }
9504a68b90caSToby Isaac     }
95059566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS,&anchors));
9506a68b90caSToby Isaac   }
9507f7c74593SToby Isaac   /* reset the generic constraints */
95089566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL));
9509a68b90caSToby Isaac   PetscFunctionReturn(0);
9510a68b90caSToby Isaac }
9511a68b90caSToby Isaac 
9512f7c74593SToby Isaac static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9513a68b90caSToby Isaac {
9514f7c74593SToby Isaac   PetscSection anchorSection;
95156995de1eSToby Isaac   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9516a68b90caSToby Isaac 
9517a68b90caSToby Isaac   PetscFunctionBegin;
9518a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL));
95209566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec));
95219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section,&numFields));
95226995de1eSToby Isaac   if (numFields) {
9523719ab38cSToby Isaac     PetscInt f;
95249566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec,numFields));
9525719ab38cSToby Isaac 
9526719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
9527719ab38cSToby Isaac       PetscInt numComp;
9528719ab38cSToby Isaac 
95299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section,f,&numComp));
95309566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp));
9531719ab38cSToby Isaac     }
95326995de1eSToby Isaac   }
95339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd));
95349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section,&sStart,&sEnd));
95356995de1eSToby Isaac   pStart = PetscMax(pStart,sStart);
95366995de1eSToby Isaac   pEnd   = PetscMin(pEnd,sEnd);
95376995de1eSToby Isaac   pEnd   = PetscMax(pStart,pEnd);
95389566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd));
9539a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
95409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection,p,&dof));
9541a68b90caSToby Isaac     if (dof) {
95429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,p,&dof));
95439566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec,p,dof));
9544a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
95459566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section,p,f,&dof));
95469566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof));
9547a68b90caSToby Isaac       }
9548a68b90caSToby Isaac     }
9549a68b90caSToby Isaac   }
95509566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
95519566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section"));
9552a68b90caSToby Isaac   PetscFunctionReturn(0);
9553a68b90caSToby Isaac }
9554a68b90caSToby Isaac 
9555f7c74593SToby Isaac static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9556a68b90caSToby Isaac {
9557f7c74593SToby Isaac   PetscSection   aSec;
9558ae65431dSMatthew G. Knepley   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
95590ac89760SToby Isaac   const PetscInt *anchors;
95600ac89760SToby Isaac   PetscInt       numFields, f;
956166ad2231SToby Isaac   IS             aIS;
9562e19f7ee6SMark Adams   MatType        mtype;
9563e19f7ee6SMark Adams   PetscBool      iscuda,iskokkos;
95640ac89760SToby Isaac 
95650ac89760SToby Isaac   PetscFunctionBegin;
95660ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
95689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
95699566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF,cMat));
95709566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat,m,n,m,n));
95719566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda));
95729566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda));
95739566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos));
95749566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos));
9575e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9576e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9577e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
95789566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat,mtype));
95799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS));
95809566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
95816995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
95829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd));
95839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section,&sStart,&sEnd));
95849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m+1,&i));
95850ac89760SToby Isaac   i[0] = 0;
95869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section,&numFields));
95870ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
9588f19733c5SToby Isaac     PetscInt rDof, rOff, r;
9589f19733c5SToby Isaac 
95909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec,p,&rDof));
9591f19733c5SToby Isaac     if (!rDof) continue;
95929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec,p,&rOff));
95930ac89760SToby Isaac     if (numFields) {
95940ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
95950ac89760SToby Isaac         annz = 0;
9596f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
9597f19733c5SToby Isaac           a = anchors[rOff + r];
9598ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
95999566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof));
96000ac89760SToby Isaac           annz += aDof;
96010ac89760SToby Isaac         }
96029566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof));
96039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off));
96040ac89760SToby Isaac         for (q = 0; q < dof; q++) {
96050ac89760SToby Isaac           i[off + q + 1] = i[off + q] + annz;
96060ac89760SToby Isaac         }
96070ac89760SToby Isaac       }
96082f7452b8SBarry Smith     } else {
96090ac89760SToby Isaac       annz = 0;
96109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&dof));
96110ac89760SToby Isaac       for (q = 0; q < dof; q++) {
9612ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
9613ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
96149566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section,a,&aDof));
96150ac89760SToby Isaac         annz += aDof;
96160ac89760SToby Isaac       }
96179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&dof));
96189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec,p,&off));
96190ac89760SToby Isaac       for (q = 0; q < dof; q++) {
96200ac89760SToby Isaac         i[off + q + 1] = i[off + q] + annz;
96210ac89760SToby Isaac       }
96220ac89760SToby Isaac     }
96230ac89760SToby Isaac   }
96240ac89760SToby Isaac   nnz = i[m];
96259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz,&j));
96260ac89760SToby Isaac   offset = 0;
96270ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
96280ac89760SToby Isaac     if (numFields) {
96290ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
96309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof));
96310ac89760SToby Isaac         for (q = 0; q < dof; q++) {
96320ac89760SToby Isaac           PetscInt rDof, rOff, r;
96339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec,p,&rDof));
96349566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec,p,&rOff));
96350ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
96360ac89760SToby Isaac             PetscInt s;
96370ac89760SToby Isaac 
96380ac89760SToby Isaac             a = anchors[rOff + r];
9639ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
96409566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof));
96419566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff));
96420ac89760SToby Isaac             for (s = 0; s < aDof; s++) {
96430ac89760SToby Isaac               j[offset++] = aOff + s;
96440ac89760SToby Isaac             }
96450ac89760SToby Isaac           }
96460ac89760SToby Isaac         }
96470ac89760SToby Isaac       }
96482f7452b8SBarry Smith     } else {
96499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&dof));
96500ac89760SToby Isaac       for (q = 0; q < dof; q++) {
96510ac89760SToby Isaac         PetscInt rDof, rOff, r;
96529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,p,&rDof));
96539566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&rOff));
96540ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
96550ac89760SToby Isaac           PetscInt s;
96560ac89760SToby Isaac 
96570ac89760SToby Isaac           a = anchors[rOff + r];
9658ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
96599566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,a,&aDof));
96609566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section,a,&aOff));
96610ac89760SToby Isaac           for (s = 0; s < aDof; s++) {
96620ac89760SToby Isaac             j[offset++] = aOff + s;
96630ac89760SToby Isaac           }
96640ac89760SToby Isaac         }
96650ac89760SToby Isaac       }
96660ac89760SToby Isaac     }
96670ac89760SToby Isaac   }
96689566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL));
96699566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
96709566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
96719566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
96720ac89760SToby Isaac   PetscFunctionReturn(0);
96730ac89760SToby Isaac }
96740ac89760SToby Isaac 
967566ad2231SToby Isaac PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
967666ad2231SToby Isaac {
9677f7c74593SToby Isaac   DM_Plex        *plex = (DM_Plex *)dm->data;
9678f7c74593SToby Isaac   PetscSection   anchorSection, section, cSec;
967966ad2231SToby Isaac   Mat            cMat;
968066ad2231SToby Isaac 
968166ad2231SToby Isaac   PetscFunctionBegin;
968266ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
96839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL));
968466ad2231SToby Isaac   if (anchorSection) {
968544a7f3ddSMatthew G. Knepley     PetscInt Nf;
9686e228b242SToby Isaac 
96879566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm,&section));
96889566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec));
96899566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat));
96909566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm,&Nf));
96919566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat));
96929566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL));
96939566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
96949566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
969566ad2231SToby Isaac   }
969666ad2231SToby Isaac   PetscFunctionReturn(0);
969766ad2231SToby Isaac }
9698a93c429eSMatthew G. Knepley 
9699a93c429eSMatthew G. Knepley PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9700a93c429eSMatthew G. Knepley {
9701a93c429eSMatthew G. Knepley   IS             subis;
9702a93c429eSMatthew G. Knepley   PetscSection   section, subsection;
9703a93c429eSMatthew G. Knepley 
9704a93c429eSMatthew G. Knepley   PetscFunctionBegin;
97059566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
970628b400f6SJacob Faibussowitsch   PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
970728b400f6SJacob Faibussowitsch   PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9708a93c429eSMatthew G. Knepley   /* Create subdomain */
97099566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dm, label, value, subdm));
9710a93c429eSMatthew G. Knepley   /* Create submodel */
97119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
97129566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
97139566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
97149566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
97159566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
9716a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
9717a93c429eSMatthew G. Knepley   if (is) {
9718a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
9719a93c429eSMatthew G. Knepley     IS              spIS;
9720a93c429eSMatthew G. Knepley     const PetscInt *spmap;
9721a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
9722a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9723a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9724a93c429eSMatthew G. Knepley 
97259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
97269566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
97279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
97289566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
97299566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
97309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
9731a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
9732a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize  = 0;
9733a93c429eSMatthew G. Knepley 
97349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
9735a93c429eSMatthew G. Knepley       if (gdof > 0) {
9736a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
9737a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
9738a93c429eSMatthew G. Knepley 
97399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
97409566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
9741a93c429eSMatthew G. Knepley           pSubSize += fdof-fcdof;
9742a93c429eSMatthew G. Knepley         }
9743a93c429eSMatthew G. Knepley         subSize += pSubSize;
9744a93c429eSMatthew G. Knepley         if (pSubSize) {
9745a93c429eSMatthew G. Knepley           if (bs < 0) {
9746a93c429eSMatthew G. Knepley             bs = pSubSize;
9747a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
9748a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
9749a93c429eSMatthew G. Knepley             bs = 1;
9750a93c429eSMatthew G. Knepley           }
9751a93c429eSMatthew G. Knepley         }
9752a93c429eSMatthew G. Knepley       }
9753a93c429eSMatthew G. Knepley     }
9754a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
9755a93c429eSMatthew G. Knepley     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
97569566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax));
9757a93c429eSMatthew G. Knepley     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9758a93c429eSMatthew G. Knepley     else                            {bs = bsMinMax[0];}
97599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
9760a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
9761a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
9762a93c429eSMatthew G. Knepley 
97639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
9764a93c429eSMatthew G. Knepley       if (gdof > 0) {
9765a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
9766a93c429eSMatthew G. Knepley 
97679566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
9768a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
9769a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
9770a93c429eSMatthew G. Knepley 
9771a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
9772a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
97739566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
97749566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
9775a93c429eSMatthew G. Knepley             poff += fdof-fcdof;
9776a93c429eSMatthew G. Knepley           }
97779566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
97789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
9779a93c429eSMatthew G. Knepley           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9780a93c429eSMatthew G. Knepley             subIndices[subOff] = goff+poff+fc;
9781a93c429eSMatthew G. Knepley           }
9782a93c429eSMatthew G. Knepley         }
9783a93c429eSMatthew G. Knepley       }
9784a93c429eSMatthew G. Knepley     }
97859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
97869566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
9787a93c429eSMatthew G. Knepley     if (bs > 1) {
9788a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
9789a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
9790a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
9791a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
9792a93c429eSMatthew G. Knepley           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9793a93c429eSMatthew G. Knepley         }
9794a93c429eSMatthew G. Knepley       }
97959566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
9796a93c429eSMatthew G. Knepley     }
9797a93c429eSMatthew G. Knepley     /* Attach nullspace */
9798a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
9799a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9800a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
9801a93c429eSMatthew G. Knepley     }
9802a93c429eSMatthew G. Knepley     if (f < Nf) {
9803a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
98049566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
98056823f3c5SBlaise Bourdin 
98069566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace));
98079566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
9808a93c429eSMatthew G. Knepley     }
9809a93c429eSMatthew G. Knepley   }
9810a93c429eSMatthew G. Knepley   PetscFunctionReturn(0);
9811a93c429eSMatthew G. Knepley }
9812c0f0dcc3SMatthew G. Knepley 
9813c0f0dcc3SMatthew G. Knepley /*@
9814c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9815c0f0dcc3SMatthew G. Knepley 
9816c0f0dcc3SMatthew G. Knepley   Input Parameter:
9817c0f0dcc3SMatthew G. Knepley - dm - The DM
9818c0f0dcc3SMatthew G. Knepley 
9819c0f0dcc3SMatthew G. Knepley   Level: developer
9820c0f0dcc3SMatthew G. Knepley 
9821c0f0dcc3SMatthew G. Knepley   Options Database Keys:
9822c0f0dcc3SMatthew G. Knepley . -dm_plex_monitor_throughput - Activate the monitor
9823c0f0dcc3SMatthew G. Knepley 
9824db781477SPatrick Sanan .seealso: `DMSetFromOptions()`, `DMPlexCreate()`
9825c0f0dcc3SMatthew G. Knepley @*/
9826c0f0dcc3SMatthew G. Knepley PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9827c0f0dcc3SMatthew G. Knepley {
9828e5ed2c37SJose E. Roman #if defined(PETSC_USE_LOG)
9829c0f0dcc3SMatthew G. Knepley   PetscStageLog      stageLog;
9830c0f0dcc3SMatthew G. Knepley   PetscLogEvent      event;
9831c0f0dcc3SMatthew G. Knepley   PetscLogStage      stage;
9832c0f0dcc3SMatthew G. Knepley   PetscEventPerfInfo eventInfo;
9833c0f0dcc3SMatthew G. Knepley   PetscReal          cellRate, flopRate;
9834c0f0dcc3SMatthew G. Knepley   PetscInt           cStart, cEnd, Nf, N;
9835c0f0dcc3SMatthew G. Knepley   const char        *name;
9836e5ed2c37SJose E. Roman #endif
9837c0f0dcc3SMatthew G. Knepley 
9838c0f0dcc3SMatthew G. Knepley   PetscFunctionBegin;
9839c0f0dcc3SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9840c0f0dcc3SMatthew G. Knepley #if defined(PETSC_USE_LOG)
98419566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
98429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
98439566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
98449566063dSJacob Faibussowitsch   PetscCall(PetscLogGetStageLog(&stageLog));
98459566063dSJacob Faibussowitsch   PetscCall(PetscStageLogGetCurrent(stageLog, &stage));
98469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
98479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo));
9848c0f0dcc3SMatthew G. Knepley   N        = (cEnd - cStart)*Nf*eventInfo.count;
9849c0f0dcc3SMatthew G. Knepley   flopRate = eventInfo.flops/eventInfo.time;
9850c0f0dcc3SMatthew G. Knepley   cellRate = N/eventInfo.time;
985163a3b9bcSJacob 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)));
9852c0f0dcc3SMatthew G. Knepley #else
9853c0f0dcc3SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9854c0f0dcc3SMatthew G. Knepley #endif
9855c0f0dcc3SMatthew G. Knepley   PetscFunctionReturn(0);
9856c0f0dcc3SMatthew G. Knepley }
9857