xref: /petsc/src/dm/impls/plex/plex.c (revision ae1ee55146a7ad071171b861759b85940c7e5c67)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2695799ffSMatthew G. Knepley #include <petsc/private/dmlabelimpl.h>
3af0996ceSBarry Smith #include <petsc/private/isimpl.h>
4e5c6e791SKarl Rupp #include <petsc/private/vecimpl.h>
58135c375SStefano Zampini #include <petsc/private/glvisvecimpl.h>
60c312b8eSJed Brown #include <petscsf.h>
7e228b242SToby Isaac #include <petscds.h>
8e412dcbdSMatthew G. Knepley #include <petscdraw.h>
9f19dbd58SToby Isaac #include <petscdmfield.h>
10012bc364SMatthew G. Knepley #include <petscdmplextransform.h>
11c789d87fSToby Isaac #include <petscblaslapack.h>
12552f7358SJed Brown 
13552f7358SJed Brown /* Logging support */
143b9d9b65SStefano Zampini PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeMultistage, 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_CreateBoxSFC, 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;
15f7b6882eSMatthew G. Knepley PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;
16ce78bad3SBarry Smith PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad;
17ce78bad3SBarry Smith 
18f39ec787SMatthew G. Knepley PetscBool  Plexcite       = PETSC_FALSE;
19f39ec787SMatthew G. Knepley const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n"
20f39ec787SMatthew G. Knepley                             "title     = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n"
21f39ec787SMatthew G. Knepley                             "author    = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n"
22f39ec787SMatthew G. Knepley                             "journal   = {SIAM Journal on Scientific Computing},\n"
23f39ec787SMatthew G. Knepley                             "volume    = {38},\n"
24f39ec787SMatthew G. Knepley                             "number    = {5},\n"
25f39ec787SMatthew G. Knepley                             "pages     = {S143--S155},\n"
26f39ec787SMatthew G. Knepley                             "eprint    = {http://arxiv.org/abs/1506.07749},\n"
27f39ec787SMatthew G. Knepley                             "doi       = {10.1137/15M1026092},\n"
28f39ec787SMatthew G. Knepley                             "year      = {2016},\n"
29f39ec787SMatthew G. Knepley                             "petsc_uses={DMPlex},\n}\n";
30f39ec787SMatthew G. Knepley 
31d6acfc2dSPierre Jolivet PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
32552f7358SJed Brown 
33e5337592SStefano Zampini /*@
349318fe57SMatthew G. Knepley   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
359318fe57SMatthew G. Knepley 
369318fe57SMatthew G. Knepley   Input Parameter:
37a1cb98faSBarry Smith . dm - The `DMPLEX` object
389318fe57SMatthew G. Knepley 
399318fe57SMatthew G. Knepley   Output Parameter:
409318fe57SMatthew G. Knepley . simplex - Flag checking for a simplex
419318fe57SMatthew G. Knepley 
429318fe57SMatthew G. Knepley   Level: intermediate
439318fe57SMatthew G. Knepley 
44a1cb98faSBarry Smith   Note:
45a1cb98faSBarry Smith   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
46a1cb98faSBarry Smith   If the mesh has no cells, this returns `PETSC_FALSE`.
47a1cb98faSBarry Smith 
481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
499318fe57SMatthew G. Knepley @*/
50d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
51d71ae5a4SJacob Faibussowitsch {
529318fe57SMatthew G. Knepley   DMPolytopeType ct;
539318fe57SMatthew G. Knepley   PetscInt       cStart, cEnd;
549318fe57SMatthew G. Knepley 
559318fe57SMatthew G. Knepley   PetscFunctionBegin;
569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
579371c9d4SSatish Balay   if (cEnd <= cStart) {
589371c9d4SSatish Balay     *simplex = PETSC_FALSE;
593ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
609371c9d4SSatish Balay   }
619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
629318fe57SMatthew G. Knepley   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
649318fe57SMatthew G. Knepley }
659318fe57SMatthew G. Knepley 
669318fe57SMatthew G. Knepley /*@
67412e9a14SMatthew G. Knepley   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
68e5337592SStefano Zampini 
69d8d19677SJose E. Roman   Input Parameters:
70a1cb98faSBarry Smith + dm     - The `DMPLEX` object
71412e9a14SMatthew G. Knepley - height - The cell height in the Plex, 0 is the default
72e5337592SStefano Zampini 
73e5337592SStefano Zampini   Output Parameters:
74ce78bad3SBarry Smith + cStart - The first "normal" cell, pass `NULL` if not needed
75ce78bad3SBarry Smith - cEnd   - The upper bound on "normal" cells, pass `NULL` if not needed
76e5337592SStefano Zampini 
77412e9a14SMatthew G. Knepley   Level: developer
78e5337592SStefano Zampini 
79a1cb98faSBarry Smith   Note:
805ae96e2bSMatthew G. Knepley   This function requires that tensor cells are ordered last.
81a1cb98faSBarry Smith 
822827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
83e5337592SStefano Zampini @*/
84ce78bad3SBarry Smith PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd)
85d71ae5a4SJacob Faibussowitsch {
865ae96e2bSMatthew G. Knepley   DMLabel         ctLabel;
875ae96e2bSMatthew G. Knepley   IS              valueIS;
885ae96e2bSMatthew G. Knepley   const PetscInt *ctypes;
895e27db3eSMatthew G. Knepley   PetscBool       found = PETSC_FALSE;
901690c2aeSBarry Smith   PetscInt        Nct, cS = PETSC_INT_MAX, cE = 0;
91e5337592SStefano Zampini 
92e5337592SStefano Zampini   PetscFunctionBegin;
939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
945ae96e2bSMatthew G. Knepley   PetscCall(DMLabelGetValueIS(ctLabel, &valueIS));
955ae96e2bSMatthew G. Knepley   PetscCall(ISGetLocalSize(valueIS, &Nct));
965ae96e2bSMatthew G. Knepley   PetscCall(ISGetIndices(valueIS, &ctypes));
975ae96e2bSMatthew G. Knepley   for (PetscInt t = 0; t < Nct; ++t) {
98c306944fSJed Brown     const DMPolytopeType ct = (DMPolytopeType)ctypes[t];
995ae96e2bSMatthew G. Knepley     PetscInt             ctS, ctE, ht;
1005ae96e2bSMatthew G. Knepley 
1015ae96e2bSMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) {
1025ae96e2bSMatthew G. Knepley       // If any cells are not typed, just use all cells
1035ae96e2bSMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd));
1045ae96e2bSMatthew G. Knepley       break;
1055ae96e2bSMatthew G. Knepley     }
106c306944fSJed Brown     if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue;
1075ae96e2bSMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE));
1085ae96e2bSMatthew G. Knepley     if (ctS >= ctE) continue;
1095ae96e2bSMatthew G. Knepley     // Check that a point has the right height
1105ae96e2bSMatthew G. Knepley     PetscCall(DMPlexGetPointHeight(dm, ctS, &ht));
1115ae96e2bSMatthew G. Knepley     if (ht != height) continue;
1125ae96e2bSMatthew G. Knepley     cS    = PetscMin(cS, ctS);
1135ae96e2bSMatthew G. Knepley     cE    = PetscMax(cE, ctE);
1145e27db3eSMatthew G. Knepley     found = PETSC_TRUE;
1155ae96e2bSMatthew G. Knepley   }
1165e27db3eSMatthew G. Knepley   if (!Nct || !found) cS = cE = 0;
1175ae96e2bSMatthew G. Knepley   PetscCall(ISDestroy(&valueIS));
118695799ffSMatthew G. Knepley   // Reset label for fast lookup
119695799ffSMatthew G. Knepley   PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
120412e9a14SMatthew G. Knepley   if (cStart) *cStart = cS;
121412e9a14SMatthew G. Knepley   if (cEnd) *cEnd = cE;
1223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
123e5337592SStefano Zampini }
124e5337592SStefano Zampini 
125cf58e07aSMatthew G. Knepley PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft)
126cf58e07aSMatthew G. Knepley {
127cf58e07aSMatthew G. Knepley   PetscInt                 cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t;
128cf58e07aSMatthew G. Knepley   PetscInt                *sStart, *sEnd;
129cf58e07aSMatthew G. Knepley   PetscViewerVTKFieldType *ft;
130cf58e07aSMatthew G. Knepley   PetscInt                 vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1];
131cf58e07aSMatthew G. Knepley   DMLabel                  depthLabel, ctLabel;
132cf58e07aSMatthew G. Knepley 
133cf58e07aSMatthew G. Knepley   PetscFunctionBegin;
134cf58e07aSMatthew G. Knepley   /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */
135cf58e07aSMatthew G. Knepley   PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1));
136cf58e07aSMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &cdim));
137cf58e07aSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
138cf58e07aSMatthew G. Knepley   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
139cf58e07aSMatthew G. Knepley   if (field >= 0) {
140cf58e07aSMatthew G. Knepley     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES]));
141cf58e07aSMatthew G. Knepley   } else {
142cf58e07aSMatthew G. Knepley     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES]));
143cf58e07aSMatthew G. Knepley   }
144cf58e07aSMatthew G. Knepley 
145cf58e07aSMatthew G. Knepley   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
146cf58e07aSMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
147cf58e07aSMatthew G. Knepley   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
148cf58e07aSMatthew G. Knepley   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
149cf58e07aSMatthew G. Knepley   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
150cf58e07aSMatthew G. Knepley     const DMPolytopeType ict = (DMPolytopeType)c;
151cf58e07aSMatthew G. Knepley     PetscInt             dep;
152cf58e07aSMatthew G. Knepley 
153cf58e07aSMatthew G. Knepley     if (ict == DM_POLYTOPE_FV_GHOST) continue;
154cf58e07aSMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
155cf58e07aSMatthew G. Knepley     if (pStart >= 0) {
156cf58e07aSMatthew G. Knepley       PetscCall(DMLabelGetValue(depthLabel, cStart, &dep));
157cf58e07aSMatthew G. Knepley       if (dep != depth - cellHeight) continue;
158cf58e07aSMatthew G. Knepley     }
159cf58e07aSMatthew G. Knepley     if (field >= 0) {
160cf58e07aSMatthew G. Knepley       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c]));
161cf58e07aSMatthew G. Knepley     } else {
162cf58e07aSMatthew G. Knepley       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c]));
163cf58e07aSMatthew G. Knepley     }
164cf58e07aSMatthew G. Knepley   }
165cf58e07aSMatthew G. Knepley 
166cf58e07aSMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
167cf58e07aSMatthew G. Knepley   *types = 0;
168cf58e07aSMatthew G. Knepley 
169cf58e07aSMatthew G. Knepley   for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) {
170cf58e07aSMatthew G. Knepley     if (globalvcdof[c]) ++(*types);
171cf58e07aSMatthew G. Knepley   }
172cf58e07aSMatthew G. Knepley 
173cf58e07aSMatthew G. Knepley   PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft));
174cf58e07aSMatthew G. Knepley   t = 0;
175cf58e07aSMatthew G. Knepley   if (globalvcdof[DM_NUM_POLYTOPES]) {
176cf58e07aSMatthew G. Knepley     sStart[t] = vStart;
177cf58e07aSMatthew G. Knepley     sEnd[t]   = vEnd;
178cf58e07aSMatthew G. Knepley     ft[t]     = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
179cf58e07aSMatthew G. Knepley     ++t;
180cf58e07aSMatthew G. Knepley   }
181cf58e07aSMatthew G. Knepley 
182cf58e07aSMatthew G. Knepley   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
183cf58e07aSMatthew G. Knepley     if (globalvcdof[c]) {
184cf58e07aSMatthew G. Knepley       const DMPolytopeType ict = (DMPolytopeType)c;
185cf58e07aSMatthew G. Knepley 
186cf58e07aSMatthew G. Knepley       PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
187cf58e07aSMatthew G. Knepley       sStart[t] = cStart;
188cf58e07aSMatthew G. Knepley       sEnd[t]   = cEnd;
189cf58e07aSMatthew G. Knepley       ft[t]     = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD;
190cf58e07aSMatthew G. Knepley       ++t;
191cf58e07aSMatthew G. Knepley     }
192cf58e07aSMatthew G. Knepley   }
193cf58e07aSMatthew G. Knepley 
194cf58e07aSMatthew G. Knepley   if (!*types) {
195cf58e07aSMatthew G. Knepley     if (field >= 0) {
196cf58e07aSMatthew G. Knepley       const char *fieldname;
197cf58e07aSMatthew G. Knepley 
198cf58e07aSMatthew G. Knepley       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
199cf58e07aSMatthew G. Knepley       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
200cf58e07aSMatthew G. Knepley     } else {
201cf58e07aSMatthew G. Knepley       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
202cf58e07aSMatthew G. Knepley     }
203cf58e07aSMatthew G. Knepley   }
204cf58e07aSMatthew G. Knepley 
205cf58e07aSMatthew G. Knepley   *ssStart = sStart;
206cf58e07aSMatthew G. Knepley   *ssEnd   = sEnd;
207cf58e07aSMatthew G. Knepley   *sft     = ft;
208cf58e07aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
209cf58e07aSMatthew G. Knepley }
210cf58e07aSMatthew G. Knepley 
211cf58e07aSMatthew G. Knepley PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft)
212cf58e07aSMatthew G. Knepley {
213cf58e07aSMatthew G. Knepley   PetscFunctionBegin;
214cf58e07aSMatthew G. Knepley   PetscCall(PetscFree3(*sStart, *sEnd, *ft));
215cf58e07aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
216cf58e07aSMatthew G. Knepley }
217cf58e07aSMatthew G. Knepley 
218d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
219d71ae5a4SJacob Faibussowitsch {
220412e9a14SMatthew G. Knepley   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
221a99a26bcSAdrian Croucher   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
2227e42fee7SMatthew G. Knepley 
2237e42fee7SMatthew G. Knepley   PetscFunctionBegin;
224e630c359SToby Isaac   *ft = PETSC_VTK_INVALID;
2259566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
2269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
2289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
2297e42fee7SMatthew G. Knepley   if (field >= 0) {
2309566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
2319566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
2327e42fee7SMatthew G. Knepley   } else {
2339566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
2349566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
2357e42fee7SMatthew G. Knepley   }
236462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
237a99a26bcSAdrian Croucher   if (globalvcdof[0]) {
2387e42fee7SMatthew G. Knepley     *sStart = vStart;
2397e42fee7SMatthew G. Knepley     *sEnd   = vEnd;
240f094498dSMatthew G. Knepley     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
2417e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_POINT_FIELD;
242a99a26bcSAdrian Croucher   } else if (globalvcdof[1]) {
2437e42fee7SMatthew G. Knepley     *sStart = cStart;
2447e42fee7SMatthew G. Knepley     *sEnd   = cEnd;
245f094498dSMatthew G. Knepley     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
2467e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_CELL_FIELD;
247e630c359SToby Isaac   } else {
248e630c359SToby Isaac     if (field >= 0) {
249e630c359SToby Isaac       const char *fieldname;
250e630c359SToby Isaac 
2519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
252835f2295SStefano Zampini       PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
253e630c359SToby Isaac     } else {
254835f2295SStefano Zampini       PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n"));
255e630c359SToby Isaac     }
256e630c359SToby Isaac   }
2573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2587e42fee7SMatthew G. Knepley }
2597e42fee7SMatthew G. Knepley 
2606913077dSMatthew G. Knepley /*@
2616913077dSMatthew G. Knepley   DMPlexVecView1D - Plot many 1D solutions on the same line graph
2626913077dSMatthew G. Knepley 
26320f4b53cSBarry Smith   Collective
2646913077dSMatthew G. Knepley 
2656913077dSMatthew G. Knepley   Input Parameters:
266a1cb98faSBarry Smith + dm     - The `DMPLEX` object
2676913077dSMatthew G. Knepley . n      - The number of vectors
2686913077dSMatthew G. Knepley . u      - The array of local vectors
269a1cb98faSBarry Smith - viewer - The `PetscViewer`
2706913077dSMatthew G. Knepley 
2716913077dSMatthew G. Knepley   Level: advanced
2726913077dSMatthew G. Knepley 
2731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
2746913077dSMatthew G. Knepley @*/
275d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
276d71ae5a4SJacob Faibussowitsch {
2778926a64eSMatthew G. Knepley   DM                 cdm;
2786913077dSMatthew G. Knepley   PetscDS            ds;
2796913077dSMatthew G. Knepley   PetscDraw          draw = NULL;
2806913077dSMatthew G. Knepley   PetscDrawLG        lg;
2816913077dSMatthew G. Knepley   Vec                coordinates;
2826913077dSMatthew G. Knepley   const PetscScalar *coords, **sol;
2836913077dSMatthew G. Knepley   PetscReal         *vals;
2846913077dSMatthew G. Knepley   PetscInt          *Nc;
2858926a64eSMatthew G. Knepley   PetscInt           Nf, Nl, vStart, vEnd, eStart, eEnd;
2866913077dSMatthew G. Knepley   char             **names;
2876913077dSMatthew G. Knepley 
2886913077dSMatthew G. Knepley   PetscFunctionBegin;
2898926a64eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
2909566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
2919566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
2929566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
2939566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponents(ds, &Nc));
2946913077dSMatthew G. Knepley 
2959566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2963ba16761SJacob Faibussowitsch   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
2979566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
2986913077dSMatthew G. Knepley 
2999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
3008926a64eSMatthew G. Knepley   for (PetscInt i = 0, l = 0; i < n; ++i) {
3016913077dSMatthew G. Knepley     const char *vname;
3026913077dSMatthew G. Knepley 
3039566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
3048926a64eSMatthew G. Knepley     for (PetscInt f = 0; f < Nf; ++f) {
3056913077dSMatthew G. Knepley       PetscObject disc;
3066913077dSMatthew G. Knepley       const char *fname;
3076913077dSMatthew G. Knepley       char        tmpname[PETSC_MAX_PATH_LEN];
3086913077dSMatthew G. Knepley 
3099566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
3106913077dSMatthew G. Knepley       /* TODO Create names for components */
3118926a64eSMatthew G. Knepley       for (PetscInt c = 0; c < Nc[f]; ++c, ++l) {
3129566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(disc, &fname));
313c6a7a370SJeremy L Thompson         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
314c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
315c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
3169566063dSJacob Faibussowitsch         PetscCall(PetscStrallocpy(tmpname, &names[l]));
3176913077dSMatthew G. Knepley       }
3186913077dSMatthew G. Knepley     }
3196913077dSMatthew G. Knepley   }
3209566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
3219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3229566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
3238926a64eSMatthew G. Knepley   for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
3248926a64eSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3258926a64eSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
3268926a64eSMatthew G. Knepley   PetscSection s;
327e6bf2fb5SMatthew G. Knepley   PetscInt     cdof, vdof;
3288926a64eSMatthew G. Knepley 
3298926a64eSMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &s));
330e6bf2fb5SMatthew G. Knepley   PetscCall(PetscSectionGetDof(s, eStart, &cdof));
331e6bf2fb5SMatthew G. Knepley   PetscCall(PetscSectionGetDof(s, vStart, &vdof));
332e6bf2fb5SMatthew G. Knepley   if (cdof) {
333e6bf2fb5SMatthew G. Knepley     if (vdof) {
3348926a64eSMatthew G. Knepley       // P_2
3358926a64eSMatthew G. Knepley       PetscInt vFirst = -1;
3368926a64eSMatthew G. Knepley 
3378926a64eSMatthew G. Knepley       for (PetscInt e = eStart; e < eEnd; ++e) {
3388926a64eSMatthew G. Knepley         PetscScalar    *xa, *xb, *svals;
3398926a64eSMatthew G. Knepley         const PetscInt *cone;
3408926a64eSMatthew G. Knepley 
3418926a64eSMatthew G. Knepley         PetscCall(DMPlexGetCone(dm, e, &cone));
3428926a64eSMatthew G. Knepley         PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa));
3438926a64eSMatthew G. Knepley         PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb));
3448926a64eSMatthew G. Knepley         if (e == eStart) vFirst = cone[0];
3458926a64eSMatthew G. Knepley         for (PetscInt i = 0; i < n; ++i) {
3468926a64eSMatthew G. Knepley           PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals));
3478926a64eSMatthew G. Knepley           for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
3488926a64eSMatthew G. Knepley         }
3498926a64eSMatthew G. Knepley         PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals));
3508926a64eSMatthew G. Knepley         if (e == eEnd - 1 && cone[1] != vFirst) {
3518926a64eSMatthew G. Knepley           for (PetscInt i = 0; i < n; ++i) {
3528926a64eSMatthew G. Knepley             PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals));
3538926a64eSMatthew G. Knepley             for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
3548926a64eSMatthew G. Knepley           }
3558926a64eSMatthew G. Knepley           PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals));
3568926a64eSMatthew G. Knepley           for (PetscInt i = 0; i < n; ++i) {
3578926a64eSMatthew G. Knepley             PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals));
3588926a64eSMatthew G. Knepley             for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
3598926a64eSMatthew G. Knepley           }
3608926a64eSMatthew G. Knepley           PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals));
3618926a64eSMatthew G. Knepley         }
3628926a64eSMatthew G. Knepley       }
3638926a64eSMatthew G. Knepley     } else {
364e6bf2fb5SMatthew G. Knepley       // P_0
365e6bf2fb5SMatthew G. Knepley       for (PetscInt e = eStart; e < eEnd; ++e) {
366e6bf2fb5SMatthew G. Knepley         PetscScalar    *xa, *xb, *svals;
367e6bf2fb5SMatthew G. Knepley         const PetscInt *cone;
368e6bf2fb5SMatthew G. Knepley 
369e6bf2fb5SMatthew G. Knepley         PetscCall(DMPlexGetCone(dm, e, &cone));
370e6bf2fb5SMatthew G. Knepley         PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa));
371e6bf2fb5SMatthew G. Knepley         PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb));
372e6bf2fb5SMatthew G. Knepley         for (PetscInt i = 0; i < n; ++i) {
373e6bf2fb5SMatthew G. Knepley           PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals));
374e6bf2fb5SMatthew G. Knepley           for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
375e6bf2fb5SMatthew G. Knepley         }
376e6bf2fb5SMatthew G. Knepley         PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals));
377e6bf2fb5SMatthew G. Knepley       }
378e6bf2fb5SMatthew G. Knepley     }
379e6bf2fb5SMatthew G. Knepley   } else if (vdof) {
3808926a64eSMatthew G. Knepley     // P_1
3818926a64eSMatthew G. Knepley     for (PetscInt v = vStart; v < vEnd; ++v) {
3826913077dSMatthew G. Knepley       PetscScalar *x, *svals;
3836913077dSMatthew G. Knepley 
3848926a64eSMatthew G. Knepley       PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x));
3858926a64eSMatthew G. Knepley       for (PetscInt i = 0; i < n; ++i) {
3869566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
3878926a64eSMatthew G. Knepley         for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
3886913077dSMatthew G. Knepley       }
3899566063dSJacob Faibussowitsch       PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
3906913077dSMatthew G. Knepley     }
391e6bf2fb5SMatthew G. Knepley   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported");
3929566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
3938926a64eSMatthew G. Knepley   for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
3948926a64eSMatthew G. Knepley   for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree3(sol, names, vals));
3966913077dSMatthew G. Knepley 
3979566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDraw(lg));
3989566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDestroy(&lg));
3993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4006913077dSMatthew G. Knepley }
4016913077dSMatthew G. Knepley 
402d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
403d71ae5a4SJacob Faibussowitsch {
4046913077dSMatthew G. Knepley   DM dm;
4056913077dSMatthew G. Knepley 
4066913077dSMatthew G. Knepley   PetscFunctionBegin;
4079566063dSJacob Faibussowitsch   PetscCall(VecGetDM(u, &dm));
4089566063dSJacob Faibussowitsch   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
4093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4106913077dSMatthew G. Knepley }
4116913077dSMatthew G. Knepley 
412d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
413d71ae5a4SJacob Faibussowitsch {
414e412dcbdSMatthew G. Knepley   DM                 dm;
415d1df6f1dSMatthew G. Knepley   PetscSection       s;
416e412dcbdSMatthew G. Knepley   PetscDraw          draw, popup;
417e412dcbdSMatthew G. Knepley   DM                 cdm;
418e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
419e412dcbdSMatthew G. Knepley   Vec                coordinates;
420c9c77995SMatthew G. Knepley   const PetscScalar *array;
421c9c77995SMatthew G. Knepley   PetscReal          lbound[3], ubound[3];
422339e3443SMatthew G. Knepley   PetscReal          vbound[2], time;
4236913077dSMatthew G. Knepley   PetscBool          flg;
424d1df6f1dSMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
425e412dcbdSMatthew G. Knepley   const char        *name;
426339e3443SMatthew G. Knepley   char               title[PETSC_MAX_PATH_LEN];
427e412dcbdSMatthew G. Knepley 
428e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
4299566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
4309566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
4319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
4329566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
4339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
4349566063dSJacob Faibussowitsch   PetscCall(DMGetCoarsenLevel(dm, &level));
4359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
4369566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
4379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
4389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
4399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
440e412dcbdSMatthew G. Knepley 
4419566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
4429566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
443e412dcbdSMatthew G. Knepley 
4449566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
445c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
4469566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
447e412dcbdSMatthew G. Knepley 
448d1df6f1dSMatthew G. Knepley   /* Could implement something like DMDASelectFields() */
449d1df6f1dSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
450d1df6f1dSMatthew G. Knepley     DM          fdm = dm;
451d1df6f1dSMatthew G. Knepley     Vec         fv  = v;
452d1df6f1dSMatthew G. Knepley     IS          fis;
453d1df6f1dSMatthew G. Knepley     char        prefix[PETSC_MAX_PATH_LEN];
454d1df6f1dSMatthew G. Knepley     const char *fname;
455d1df6f1dSMatthew G. Knepley 
4569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
4579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(s, f, &fname));
458d1df6f1dSMatthew G. Knepley 
4599566063dSJacob Faibussowitsch     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
460ad540459SPierre Jolivet     else prefix[0] = '\0';
461d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
4629566063dSJacob Faibussowitsch       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
4639566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(v, fis, &fv));
4649566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
4659566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
466d1df6f1dSMatthew G. Knepley     }
467d1df6f1dSMatthew G. Knepley     for (comp = 0; comp < Nc; ++comp, ++w) {
468d1df6f1dSMatthew G. Knepley       PetscInt nmax = 2;
469d1df6f1dSMatthew G. Knepley 
4709566063dSJacob Faibussowitsch       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
47163a3b9bcSJacob Faibussowitsch       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
47263a3b9bcSJacob Faibussowitsch       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
4739566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetTitle(draw, title));
474d1df6f1dSMatthew G. Knepley 
475d1df6f1dSMatthew G. Knepley       /* TODO Get max and min only for this component */
4769566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
477339e3443SMatthew G. Knepley       if (!flg) {
4789566063dSJacob Faibussowitsch         PetscCall(VecMin(fv, NULL, &vbound[0]));
4799566063dSJacob Faibussowitsch         PetscCall(VecMax(fv, NULL, &vbound[1]));
480d1df6f1dSMatthew G. Knepley         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
481339e3443SMatthew G. Knepley       }
482c9c77995SMatthew G. Knepley 
4839566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetPopup(draw, &popup));
4849566063dSJacob Faibussowitsch       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
485c9c77995SMatthew G. Knepley       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
4869566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(fv, &array));
487e412dcbdSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
488b7550097SMatthew G. Knepley         DMPolytopeType     ct;
48999a2f7bcSMatthew G. Knepley         PetscScalar       *coords = NULL, *a = NULL;
490c9c77995SMatthew G. Knepley         const PetscScalar *coords_arr;
491c9c77995SMatthew G. Knepley         PetscBool          isDG;
4926497c311SBarry Smith         PetscInt           numCoords;
4936497c311SBarry Smith         int                color[4] = {-1, -1, -1, -1};
494e412dcbdSMatthew G. Knepley 
495b7550097SMatthew G. Knepley         PetscCall(DMPlexGetCellType(dm, c, &ct));
4969566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
497339e3443SMatthew G. Knepley         if (a) {
498d1df6f1dSMatthew G. Knepley           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
499339e3443SMatthew G. Knepley           color[1] = color[2] = color[3] = color[0];
500339e3443SMatthew G. Knepley         } else {
501339e3443SMatthew G. Knepley           PetscScalar *vals = NULL;
502339e3443SMatthew G. Knepley           PetscInt     numVals, va;
503339e3443SMatthew G. Knepley 
5049566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
505b7550097SMatthew G. Knepley           if (!numVals) {
506b7550097SMatthew G. Knepley             PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
507b7550097SMatthew G. Knepley             continue;
508b7550097SMatthew G. Knepley           }
50963a3b9bcSJacob 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);
510d1df6f1dSMatthew G. Knepley           switch (numVals / Nc) {
511b7550097SMatthew G. Knepley           case 1: /* P1 Clamped Segment Prism */
512b7550097SMatthew G. Knepley           case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */
513b7550097SMatthew G. Knepley             PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]);
514b7550097SMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
515b7550097SMatthew G. Knepley             break;
516d1df6f1dSMatthew G. Knepley           case 3: /* P1 Triangle */
517d1df6f1dSMatthew G. Knepley           case 4: /* P1 Quadrangle */
518b7550097SMatthew G. Knepley             PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]);
519d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
520339e3443SMatthew G. Knepley             break;
521d1df6f1dSMatthew G. Knepley           case 6: /* P2 Triangle */
522d1df6f1dSMatthew G. Knepley           case 8: /* P2 Quadrangle */
523b7550097SMatthew G. Knepley             PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]);
524d1df6f1dSMatthew 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]);
525d1df6f1dSMatthew G. Knepley             break;
526d71ae5a4SJacob Faibussowitsch           default:
527d71ae5a4SJacob Faibussowitsch             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
528339e3443SMatthew G. Knepley           }
5299566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
530339e3443SMatthew G. Knepley         }
531c9c77995SMatthew G. Knepley         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
532e412dcbdSMatthew G. Knepley         switch (numCoords) {
533e412dcbdSMatthew G. Knepley         case 6:
5349edc3542SMatthew Knepley         case 12: /* Localized triangle */
5359566063dSJacob 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]));
536e412dcbdSMatthew G. Knepley           break;
537e412dcbdSMatthew G. Knepley         case 8:
5389edc3542SMatthew Knepley         case 16: /* Localized quadrilateral */
539b7550097SMatthew G. Knepley           if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) {
540b7550097SMatthew G. Knepley             PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1])));
541b7550097SMatthew G. Knepley           } else {
5429566063dSJacob 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]));
5439566063dSJacob 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]));
544b7550097SMatthew G. Knepley           }
545e412dcbdSMatthew G. Knepley           break;
546d71ae5a4SJacob Faibussowitsch         default:
547d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
548e412dcbdSMatthew G. Knepley         }
549c9c77995SMatthew G. Knepley         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
550e412dcbdSMatthew G. Knepley       }
5519566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(fv, &array));
5529566063dSJacob Faibussowitsch       PetscCall(PetscDrawFlush(draw));
5539566063dSJacob Faibussowitsch       PetscCall(PetscDrawPause(draw));
5549566063dSJacob Faibussowitsch       PetscCall(PetscDrawSave(draw));
555d1df6f1dSMatthew G. Knepley     }
556d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
5579566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(v, fis, &fv));
5589566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&fis));
5599566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&fdm));
560d1df6f1dSMatthew G. Knepley     }
561d1df6f1dSMatthew G. Knepley   }
5623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
563e412dcbdSMatthew G. Knepley }
564e412dcbdSMatthew G. Knepley 
565d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
566d71ae5a4SJacob Faibussowitsch {
5676913077dSMatthew G. Knepley   DM        dm;
5686913077dSMatthew G. Knepley   PetscDraw draw;
5696913077dSMatthew G. Knepley   PetscInt  dim;
5706913077dSMatthew G. Knepley   PetscBool isnull;
5716913077dSMatthew G. Knepley 
5726913077dSMatthew G. Knepley   PetscFunctionBegin;
5739566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
5749566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
5753ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
5766913077dSMatthew G. Knepley 
5779566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
5789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
5796913077dSMatthew G. Knepley   switch (dim) {
580d71ae5a4SJacob Faibussowitsch   case 1:
581d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
582d71ae5a4SJacob Faibussowitsch     break;
583d71ae5a4SJacob Faibussowitsch   case 2:
584d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
585d71ae5a4SJacob Faibussowitsch     break;
586d71ae5a4SJacob Faibussowitsch   default:
587d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
5886913077dSMatthew G. Knepley   }
5893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5906913077dSMatthew G. Knepley }
5916913077dSMatthew G. Knepley 
592d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
593d71ae5a4SJacob Faibussowitsch {
594684b87d9SLisandro Dalcin   DM                      dm;
595684b87d9SLisandro Dalcin   Vec                     locv;
596684b87d9SLisandro Dalcin   const char             *name;
597684b87d9SLisandro Dalcin   PetscSection            section;
598684b87d9SLisandro Dalcin   PetscInt                pStart, pEnd;
599e630c359SToby Isaac   PetscInt                numFields;
600684b87d9SLisandro Dalcin   PetscViewerVTKFieldType ft;
601684b87d9SLisandro Dalcin 
602684b87d9SLisandro Dalcin   PetscFunctionBegin;
6039566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
6049566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
6059566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
6069566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)locv, name));
6079566063dSJacob Faibussowitsch   PetscCall(VecCopy(v, locv));
6089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
6099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
610e630c359SToby Isaac   if (!numFields) {
6119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
6129566063dSJacob Faibussowitsch     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
613e630c359SToby Isaac   } else {
614e630c359SToby Isaac     PetscInt f;
615e630c359SToby Isaac 
616e630c359SToby Isaac     for (f = 0; f < numFields; f++) {
6179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
618e630c359SToby Isaac       if (ft == PETSC_VTK_INVALID) continue;
6199566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)locv));
6209566063dSJacob Faibussowitsch       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
621e630c359SToby Isaac     }
6229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locv));
623e630c359SToby Isaac   }
6243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
625684b87d9SLisandro Dalcin }
626684b87d9SLisandro Dalcin 
627d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
628d71ae5a4SJacob Faibussowitsch {
629552f7358SJed Brown   DM        dm;
6308926a64eSMatthew G. Knepley   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython;
631552f7358SJed Brown 
632552f7358SJed Brown   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, PETSCVIEWERVTK, &isvtk));
6369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
6389566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
6395f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
6408926a64eSMatthew G. Knepley   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
6418926a64eSMatthew G. Knepley   if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) {
642684b87d9SLisandro Dalcin     PetscInt    i, numFields;
643684b87d9SLisandro Dalcin     PetscObject fe;
644ef31f671SMatthew G. Knepley     PetscBool   fem  = PETSC_FALSE;
645684b87d9SLisandro Dalcin     Vec         locv = v;
646684b87d9SLisandro Dalcin     const char *name;
647684b87d9SLisandro Dalcin     PetscInt    step;
648684b87d9SLisandro Dalcin     PetscReal   time;
649ef31f671SMatthew G. Knepley 
6509566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &numFields));
651684b87d9SLisandro Dalcin     for (i = 0; i < numFields; i++) {
6529566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, i, NULL, &fe));
6539371c9d4SSatish Balay       if (fe->classid == PETSCFE_CLASSID) {
6549371c9d4SSatish Balay         fem = PETSC_TRUE;
6559371c9d4SSatish Balay         break;
6569371c9d4SSatish Balay       }
657ef31f671SMatthew G. Knepley     }
658684b87d9SLisandro Dalcin     if (fem) {
659798534f6SMatthew G. Knepley       PetscObject isZero;
660798534f6SMatthew G. Knepley 
6619566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &locv));
6629566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)v, &name));
6639566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)locv, name));
6649566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
6659566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
6669566063dSJacob Faibussowitsch       PetscCall(VecCopy(v, locv));
6679566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
6689566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
669ef31f671SMatthew G. Knepley     }
670552f7358SJed Brown     if (isvtk) {
6719566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
672b136c2c9SMatthew G. Knepley     } else if (ishdf5) {
673b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6749566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
675b136c2c9SMatthew G. Knepley #else
676b136c2c9SMatthew G. Knepley       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
677b136c2c9SMatthew G. Knepley #endif
678f13a32a3SMatthew G. Knepley     } else if (isdraw) {
6799566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
6808926a64eSMatthew G. Knepley     } else if (ispython) {
6818926a64eSMatthew G. Knepley       PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv));
682684b87d9SLisandro Dalcin     } else if (isglvis) {
6839566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
6849566063dSJacob Faibussowitsch       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
6859566063dSJacob Faibussowitsch       PetscCall(VecView_GLVis(locv, viewer));
6865f34f2dcSJed Brown     } else if (iscgns) {
6875f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
6885f34f2dcSJed Brown       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
6895f34f2dcSJed Brown #else
6905f34f2dcSJed Brown       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
6915f34f2dcSJed Brown #endif
692684b87d9SLisandro Dalcin     }
693798534f6SMatthew G. Knepley     if (fem) {
6949566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
6959566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &locv));
696798534f6SMatthew G. Knepley     }
697552f7358SJed Brown   } else {
698684b87d9SLisandro Dalcin     PetscBool isseq;
699684b87d9SLisandro Dalcin 
7009566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
7019566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
7029566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
703552f7358SJed Brown   }
7043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
705552f7358SJed Brown }
706552f7358SJed Brown 
707d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
708d71ae5a4SJacob Faibussowitsch {
709552f7358SJed Brown   DM        dm;
7108926a64eSMatthew G. Knepley   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython;
711552f7358SJed Brown 
712552f7358SJed Brown   PetscFunctionBegin;
7139566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
71428b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
7169566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7179566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
7189566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
7195f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
7209566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
7218926a64eSMatthew G. Knepley   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
7228926a64eSMatthew G. Knepley   if (isvtk || isdraw || isglvis || iscgns || ispython) {
723552f7358SJed Brown     Vec         locv;
724798534f6SMatthew G. Knepley     PetscObject isZero;
725552f7358SJed Brown     const char *name;
726552f7358SJed Brown 
7279566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &locv));
7289566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
7299566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)locv, name));
7309566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
7319566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
7329566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
7339566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
7349566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_Local(locv, viewer));
7359566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
7369566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &locv));
737b136c2c9SMatthew G. Knepley   } else if (ishdf5) {
738b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
7399566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
740b136c2c9SMatthew G. Knepley #else
741b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
742b136c2c9SMatthew G. Knepley #endif
7436823f3c5SBlaise Bourdin   } else if (isexodusii) {
7446823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
7459566063dSJacob Faibussowitsch     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
7466823f3c5SBlaise Bourdin #else
7476823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
7486823f3c5SBlaise Bourdin #endif
749552f7358SJed Brown   } else {
750684b87d9SLisandro Dalcin     PetscBool isseq;
751684b87d9SLisandro Dalcin 
7529566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
7539566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
7549566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
755552f7358SJed Brown   }
7563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
757552f7358SJed Brown }
758552f7358SJed Brown 
759d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
760d71ae5a4SJacob Faibussowitsch {
761d930f514SMatthew G. Knepley   DM                dm;
762d930f514SMatthew G. Knepley   MPI_Comm          comm;
763d930f514SMatthew G. Knepley   PetscViewerFormat format;
764d930f514SMatthew G. Knepley   Vec               v;
765d930f514SMatthew G. Knepley   PetscBool         isvtk, ishdf5;
766d930f514SMatthew G. Knepley 
767d930f514SMatthew G. Knepley   PetscFunctionBegin;
7689566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
7699566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
77028b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7719566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
7729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
774d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
775a8ad634aSStefano Zampini     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
776a8ad634aSStefano Zampini     /* this need a better fix */
777a8ad634aSStefano Zampini     if (dm->useNatural) {
778d930f514SMatthew G. Knepley       const char *vecname;
779d930f514SMatthew G. Knepley       PetscInt    n, nroots;
780d930f514SMatthew G. Knepley 
781966bd95aSPierre Jolivet       PetscCheck(dm->sfNatural, comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
7829566063dSJacob Faibussowitsch       PetscCall(VecGetLocalSize(originalv, &n));
7839566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
784966bd95aSPierre Jolivet       PetscCheck(n == nroots, comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
785f16a8b29SMatthew G. Knepley       PetscCall(DMPlexCreateNaturalVector(dm, &v));
7869566063dSJacob Faibussowitsch       PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
7879566063dSJacob Faibussowitsch       PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
7889566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
7899566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)v, vecname));
790a8ad634aSStefano Zampini     } else v = originalv;
791a8ad634aSStefano Zampini   } else v = originalv;
792a8ad634aSStefano Zampini 
793d930f514SMatthew G. Knepley   if (ishdf5) {
794d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
7959566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
796d930f514SMatthew G. Knepley #else
797d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
798d930f514SMatthew G. Knepley #endif
799d930f514SMatthew G. Knepley   } else if (isvtk) {
800d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
801d930f514SMatthew G. Knepley   } else {
802d930f514SMatthew G. Knepley     PetscBool isseq;
803d930f514SMatthew G. Knepley 
8049566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
8059566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
8069566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
807d930f514SMatthew G. Knepley   }
808f16a8b29SMatthew G. Knepley   if (v != originalv) PetscCall(VecDestroy(&v));
8093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
810d930f514SMatthew G. Knepley }
811d930f514SMatthew G. Knepley 
812d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
813d71ae5a4SJacob Faibussowitsch {
8142c40f234SMatthew G. Knepley   DM        dm;
8152c40f234SMatthew G. Knepley   PetscBool ishdf5;
8162c40f234SMatthew G. Knepley 
8172c40f234SMatthew G. Knepley   PetscFunctionBegin;
8189566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
81928b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
8209566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
8212c40f234SMatthew G. Knepley   if (ishdf5) {
8222c40f234SMatthew G. Knepley     DM          dmBC;
8232c40f234SMatthew G. Knepley     Vec         gv;
8242c40f234SMatthew G. Knepley     const char *name;
8252c40f234SMatthew G. Knepley 
8269566063dSJacob Faibussowitsch     PetscCall(DMGetOutputDM(dm, &dmBC));
8279566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmBC, &gv));
8289566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
8299566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)gv, name));
8309566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(gv, viewer));
8319566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
8329566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
8339566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
8341baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
8353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8362c40f234SMatthew G. Knepley }
8372c40f234SMatthew G. Knepley 
838d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
839d71ae5a4SJacob Faibussowitsch {
8402c40f234SMatthew G. Knepley   DM        dm;
841472b9844SJames Wright   PetscBool ishdf5, isexodusii, iscgns;
8422c40f234SMatthew G. Knepley 
8432c40f234SMatthew G. Knepley   PetscFunctionBegin;
8449566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
84528b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
8469566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
8479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
848472b9844SJames Wright   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
8492c40f234SMatthew G. Knepley   if (ishdf5) {
850878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
8519566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
852b136c2c9SMatthew G. Knepley #else
853b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
854878b459fSMatthew G. Knepley #endif
8556823f3c5SBlaise Bourdin   } else if (isexodusii) {
8566823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
8579566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
8586823f3c5SBlaise Bourdin #else
8596823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
8606823f3c5SBlaise Bourdin #endif
861472b9844SJames Wright   } else if (iscgns) {
862472b9844SJames Wright #if defined(PETSC_HAVE_CGNS)
863472b9844SJames Wright     PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer));
864472b9844SJames Wright #else
865472b9844SJames Wright     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
866472b9844SJames Wright #endif
8671baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
8683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
869552f7358SJed Brown }
870552f7358SJed Brown 
871d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
872d71ae5a4SJacob Faibussowitsch {
873d930f514SMatthew G. Knepley   DM                dm;
874d930f514SMatthew G. Knepley   PetscViewerFormat format;
875d930f514SMatthew G. Knepley   PetscBool         ishdf5;
876d930f514SMatthew G. Knepley 
877d930f514SMatthew G. Knepley   PetscFunctionBegin;
8789566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
87928b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
8809566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
8819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
882d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
883a8ad634aSStefano Zampini     if (dm->useNatural) {
884d930f514SMatthew G. Knepley       if (dm->sfNatural) {
885d930f514SMatthew G. Knepley         if (ishdf5) {
886d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
887d930f514SMatthew G. Knepley           Vec         v;
888d930f514SMatthew G. Knepley           const char *vecname;
889d930f514SMatthew G. Knepley 
890f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
8919566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
8929566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
8939566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
8949566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
8959566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
896f16a8b29SMatthew G. Knepley           PetscCall(VecDestroy(&v));
897d930f514SMatthew G. Knepley #else
898d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
899d930f514SMatthew G. Knepley #endif
900d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
901d930f514SMatthew G. Knepley       }
9021baa6e33SBarry Smith     } else PetscCall(VecLoad_Default(originalv, viewer));
903d930f514SMatthew G. Knepley   }
9043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
905d930f514SMatthew G. Knepley }
906d930f514SMatthew G. Knepley 
907d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
908d71ae5a4SJacob Faibussowitsch {
909731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
910731e8ddeSMatthew G. Knepley   Vec                coordinates;
911ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
912731e8ddeSMatthew G. Knepley   const char        *name[4];
913731e8ddeSMatthew G. Knepley   const PetscScalar *a;
914731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
915731e8ddeSMatthew G. Knepley 
916731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
9179566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9189566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
9199566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
9209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
9219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
9229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
9249566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
925731e8ddeSMatthew G. Knepley   name[0]       = "vertex";
926731e8ddeSMatthew G. Knepley   name[1]       = "edge";
927731e8ddeSMatthew G. Knepley   name[dim - 1] = "face";
928731e8ddeSMatthew G. Knepley   name[dim]     = "cell";
929731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
930731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
931ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
932731e8ddeSMatthew G. Knepley 
9339566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
93463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
9359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9369566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
937731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
938731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
939731e8ddeSMatthew G. Knepley 
940731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
9419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
942731e8ddeSMatthew G. Knepley       if (!dof) continue;
9439566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
9449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
94563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
946731e8ddeSMatthew G. Knepley       for (p = 0; p < dof / dim; ++p) {
9479566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
948731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
9499566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
9509566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
951731e8ddeSMatthew G. Knepley         }
9529566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
953731e8ddeSMatthew G. Knepley       }
9549566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
955731e8ddeSMatthew G. Knepley     }
9569566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9579566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
958731e8ddeSMatthew G. Knepley   }
9599566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
9603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
961731e8ddeSMatthew G. Knepley }
962731e8ddeSMatthew G. Knepley 
9639371c9d4SSatish Balay typedef enum {
9649371c9d4SSatish Balay   CS_CARTESIAN,
9659371c9d4SSatish Balay   CS_POLAR,
9669371c9d4SSatish Balay   CS_CYLINDRICAL,
9679371c9d4SSatish Balay   CS_SPHERICAL
9689371c9d4SSatish Balay } CoordSystem;
96919ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
97019ad8254SMatthew G. Knepley 
971d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
972d71ae5a4SJacob Faibussowitsch {
97319ad8254SMatthew G. Knepley   PetscInt i;
97419ad8254SMatthew G. Knepley 
97519ad8254SMatthew G. Knepley   PetscFunctionBegin;
97619ad8254SMatthew G. Knepley   if (dim > 3) {
9779566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
97819ad8254SMatthew G. Knepley   } else {
979bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
98019ad8254SMatthew G. Knepley 
98119ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
98219ad8254SMatthew G. Knepley     switch (cs) {
9839371c9d4SSatish Balay     case CS_CARTESIAN:
9849371c9d4SSatish Balay       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
9859371c9d4SSatish Balay       break;
98619ad8254SMatthew G. Knepley     case CS_POLAR:
98763a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
98819ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
98919ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
99019ad8254SMatthew G. Knepley       break;
99119ad8254SMatthew G. Knepley     case CS_CYLINDRICAL:
99263a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
99319ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
99419ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
99519ad8254SMatthew G. Knepley       trcoords[2] = coords[2];
99619ad8254SMatthew G. Knepley       break;
99719ad8254SMatthew G. Knepley     case CS_SPHERICAL:
99863a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
99919ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
100019ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
100119ad8254SMatthew G. Knepley       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
100219ad8254SMatthew G. Knepley       break;
100319ad8254SMatthew G. Knepley     }
10049566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
100519ad8254SMatthew G. Knepley   }
10063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100719ad8254SMatthew G. Knepley }
100819ad8254SMatthew G. Knepley 
1009d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
1010d71ae5a4SJacob Faibussowitsch {
1011552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex *)dm->data;
10126858538eSMatthew G. Knepley   DM                cdm, cdmCell;
10136858538eSMatthew G. Knepley   PetscSection      coordSection, coordSectionCell;
10146858538eSMatthew G. Knepley   Vec               coordinates, coordinatesCell;
1015552f7358SJed Brown   PetscViewerFormat format;
1016552f7358SJed Brown 
1017552f7358SJed Brown   PetscFunctionBegin;
10189566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
1019552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1020552f7358SJed Brown     const char *name;
1021f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
10229318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
1023552f7358SJed Brown     PetscMPIInt rank, size;
1024552f7358SJed Brown 
10259f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
10269f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
10279f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
10289f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
10299f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
10309f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
10319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
10329566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
10339566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
10349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
10359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
10369566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
10379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
103863a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
103963a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
104063a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
104163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
10429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
104363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
1044552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
1045552f7358SJed Brown       PetscInt dof, off, s;
1046552f7358SJed Brown 
10479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
10489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
104948a46eb9SPierre Jolivet       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
1050552f7358SJed Brown     }
10519566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
105263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
105363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
1054552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
1055552f7358SJed Brown       PetscInt dof, off, c;
1056552f7358SJed Brown 
10579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
10589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
105948a46eb9SPierre Jolivet       for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
1060552f7358SJed Brown     }
10619566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
10629566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
10633d2e540fSStefano Zampini     if (coordSection && coordinates) {
106419ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
10656858538eSMatthew G. Knepley       const PetscScalar *array, *arrayCell = NULL;
10661690c2aeSBarry Smith       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p;
106719ad8254SMatthew G. Knepley       PetscMPIInt        rank;
106819ad8254SMatthew G. Knepley       const char        *name;
106919ad8254SMatthew G. Knepley 
10709566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
10719566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
10729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
107363a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
10749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
10756858538eSMatthew G. Knepley       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
10766858538eSMatthew G. Knepley       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
10776858538eSMatthew G. Knepley       pStart = PetscMin(pvStart, pcStart);
10786858538eSMatthew G. Knepley       pEnd   = PetscMax(pvEnd, pcEnd);
10799566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
108063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
108163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
10829566063dSJacob Faibussowitsch       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
108319ad8254SMatthew G. Knepley 
10849566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordinates, &array));
10856858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
10869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
10879566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
108819ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
108919ad8254SMatthew G. Knepley         PetscInt dof, off;
109019ad8254SMatthew G. Knepley 
10916858538eSMatthew G. Knepley         if (p >= pvStart && p < pvEnd) {
10929566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
10939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
10946858538eSMatthew G. Knepley           if (dof) {
1095f2719977SBarry Smith             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
10969566063dSJacob Faibussowitsch             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
10979566063dSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
109819ad8254SMatthew G. Knepley           }
10996858538eSMatthew G. Knepley         }
11006858538eSMatthew G. Knepley         if (cdmCell && p >= pcStart && p < pcEnd) {
11016858538eSMatthew G. Knepley           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
11026858538eSMatthew G. Knepley           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
11036858538eSMatthew G. Knepley           if (dof) {
1104f2719977SBarry Smith             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
11056858538eSMatthew G. Knepley             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
11066858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
11076858538eSMatthew G. Knepley           }
11086858538eSMatthew G. Knepley         }
11096858538eSMatthew G. Knepley       }
11109566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
11119566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
11129566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
11136858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
11143d2e540fSStefano Zampini     }
11159566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
11169566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
11179318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
11189318fe57SMatthew G. Knepley       DMLabel     label;
11199318fe57SMatthew G. Knepley       PetscBool   isdepth;
11209318fe57SMatthew G. Knepley       const char *name;
11219318fe57SMatthew G. Knepley 
11229566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
11239566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
11249318fe57SMatthew G. Knepley       if (isdepth) continue;
11259566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
11269566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
11279318fe57SMatthew G. Knepley     }
1128552f7358SJed Brown     if (size > 1) {
1129552f7358SJed Brown       PetscSF sf;
1130552f7358SJed Brown 
11319566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
11329566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
1133552f7358SJed Brown     }
11341fca310dSJames Wright     if (mesh->periodic.face_sfs)
11351fca310dSJames Wright       for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer));
11369566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1137552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
11380588280cSMatthew G. Knepley     const char  *name, *color;
11390588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
11400588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
1141fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
1142552f7358SJed Brown     PetscReal    scale      = 2.0;
114378081901SStefano Zampini     PetscReal    tikzscale  = 1.0;
1144b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
11450588280cSMatthew G. Knepley     double       tcoords[3];
1146552f7358SJed Brown     PetscScalar *coords;
1147b862f699SMatthew G. Knepley     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n;
1148552f7358SJed Brown     PetscMPIInt  rank, size;
11490588280cSMatthew G. Knepley     char       **names, **colors, **lcolors;
1150b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
1151fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
1152fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
1153552f7358SJed Brown 
11549f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
11559f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
11569f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
11579f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
11589f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
11599f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
11609566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
11619566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
11629566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
11630588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
11640588280cSMatthew G. Knepley     numColors  = 10;
11650588280cSMatthew G. Knepley     numLColors = 10;
11669566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
11679566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
11689566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
11699566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
1170b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
1171b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
1172b7f6ffafSMatthew G. Knepley     n = 4;
11739566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
11741dca8a05SBarry 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);
1175bd3611e6SMatthew G. Knepley     n = 4;
11769566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
11771dca8a05SBarry 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);
11789566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
11790588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
11809566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
11810588280cSMatthew G. Knepley     if (!useColors) {
11820588280cSMatthew G. Knepley       numColors = 3;
11839566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
11840588280cSMatthew G. Knepley     }
11859566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
11860588280cSMatthew G. Knepley     if (!useColors) {
11870588280cSMatthew G. Knepley       numLColors = 4;
11889566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
11890588280cSMatthew G. Knepley     }
11909566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1191b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
11929566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
11931dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1194202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
11959566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
1196fe1cc32dSStefano Zampini 
1197fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
11989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
12009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
12019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1202b862f699SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
1203fe1cc32dSStefano Zampini     if (lflg) {
1204fe1cc32dSStefano Zampini       DMLabel lbl;
1205fe1cc32dSStefano Zampini 
12069566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
1207fe1cc32dSStefano Zampini       if (lbl) {
1208fe1cc32dSStefano Zampini         PetscInt val, defval;
1209fe1cc32dSStefano Zampini 
12109566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
12119566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1212fe1cc32dSStefano Zampini         for (c = pStart; c < pEnd; c++) {
1213fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
1214fe1cc32dSStefano Zampini           PetscInt  closureSize;
1215fe1cc32dSStefano Zampini 
12169566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
1217fe1cc32dSStefano Zampini           if (val == defval) continue;
1218fe1cc32dSStefano Zampini 
12199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
122048a46eb9SPierre Jolivet           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
12219566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1222fe1cc32dSStefano Zampini         }
1223fe1cc32dSStefano Zampini       }
1224fe1cc32dSStefano Zampini     }
1225fe1cc32dSStefano Zampini 
12269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
12279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
12289566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
12299566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
12300588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
1231552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
1232552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
1233552f7358SJed Brown \\usetikzlibrary{arrows}\n\
12345f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
12350588280cSMatthew G. Knepley     if (size > 1) {
12369566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1237770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
123863a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
123963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1240770b213bSMatthew G Knepley       }
12419566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
12420588280cSMatthew G. Knepley     }
1243b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1244b862f699SMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart)));
1245b7f6ffafSMatthew G. Knepley 
124663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
124763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
124863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
12499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
125063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
125163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
12529566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
125363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
1254b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart));
1255b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1));
1256b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.));
1257b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart));
125863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
125963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
126063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
12619566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1262b7f6ffafSMatthew G. Knepley     }
12639566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1264fe1cc32dSStefano Zampini 
1265552f7358SJed Brown     /* Plot vertices */
12669566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
12679566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1268552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1269552f7358SJed Brown       PetscInt  off, dof, d;
12700588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1271552f7358SJed Brown 
1272fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
12739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
12749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
12759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
127663a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
12770588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
12780588280cSMatthew G. Knepley         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1279c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
12800588280cSMatthew G. Knepley       }
12810588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
12829371c9d4SSatish Balay       if (dim == 3) {
12839371c9d4SSatish Balay         PetscReal tmp = tcoords[1];
12849371c9d4SSatish Balay         tcoords[1]    = tcoords[2];
12859371c9d4SSatish Balay         tcoords[2]    = -tmp;
12869371c9d4SSatish Balay       }
1287552f7358SJed Brown       for (d = 0; d < dof; ++d) {
12889566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1289835f2295SStefano Zampini         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]));
1290552f7358SJed Brown       }
1291b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0 % numColors];
1292b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
12930588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
12940588280cSMatthew G. Knepley         PetscInt val;
12959566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
12969371c9d4SSatish Balay         if (val >= 0) {
12979371c9d4SSatish Balay           color     = lcolors[l % numLColors];
12989371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
12999371c9d4SSatish Balay           break;
13009371c9d4SSatish Balay         }
13010588280cSMatthew G. Knepley       }
1302b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
130363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1304b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
130563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
13061baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1307552f7358SJed Brown     }
13089566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
13099566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1310b7f6ffafSMatthew G. Knepley     /* Plot edges */
1311b7f6ffafSMatthew G. Knepley     if (plotEdges) {
13129566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
13139566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1314b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1315b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1316b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1317b7f6ffafSMatthew G. Knepley 
1318b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
13199566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
132063a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
13219566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
13229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
13239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
13249566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
13259566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1326b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1327835f2295SStefano Zampini           tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2);
1328b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1329b7f6ffafSMatthew G. Knepley         }
1330b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
13319371c9d4SSatish Balay         if (dim == 3) {
13329371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
13339371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
13349371c9d4SSatish Balay           tcoords[2]    = -tmp;
13359371c9d4SSatish Balay         }
1336b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
13379566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1338835f2295SStefano Zampini           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]));
1339b7f6ffafSMatthew G. Knepley         }
1340b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1 % numColors];
1341b7f6ffafSMatthew G. Knepley         else color = colors[rank % numColors];
1342b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1343b7f6ffafSMatthew G. Knepley           PetscInt val;
1344bd3611e6SMatthew G. Knepley           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
13459371c9d4SSatish Balay           if (val >= 0) {
13469371c9d4SSatish Balay             color = lcolors[l % numLColors];
13479371c9d4SSatish Balay             break;
13489371c9d4SSatish Balay           }
1349b7f6ffafSMatthew G. Knepley         }
135063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1351b7f6ffafSMatthew G. Knepley       }
13529566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
13539566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
13549566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1355b7f6ffafSMatthew G. Knepley     }
1356846a3e8bSMatthew G. Knepley     /* Plot cells */
1357b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1358846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1359846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1360846a3e8bSMatthew G. Knepley 
1361fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1362846a3e8bSMatthew G. Knepley         color = colors[rank % numColors];
1363846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1364846a3e8bSMatthew G. Knepley           PetscInt val;
13659566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
13669371c9d4SSatish Balay           if (val >= 0) {
13679371c9d4SSatish Balay             color = lcolors[l % numLColors];
13689371c9d4SSatish Balay             break;
13699371c9d4SSatish Balay           }
1370846a3e8bSMatthew G. Knepley         }
13719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
137263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1373846a3e8bSMatthew G. Knepley       }
1374846a3e8bSMatthew G. Knepley     } else {
1375b7f6ffafSMatthew G. Knepley       DMPolytopeType ct;
1376846a3e8bSMatthew G. Knepley 
1377b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1378b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1379fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
13809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
1381c306944fSJed Brown         if (DMPolytopeTypeIsHybrid(ct)) {
1382b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1383b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1384b7f6ffafSMatthew G. Knepley 
13859566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
13869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1387b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1388b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1389b7f6ffafSMatthew G. Knepley 
13909566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
139163a3b9bcSJacob 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));
1392b7f6ffafSMatthew G. Knepley           }
1393b7f6ffafSMatthew G. Knepley         } else {
1394b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1395b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1396b7f6ffafSMatthew G. Knepley 
13979566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1398846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize * 2; p += 2) {
1399846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1400846a3e8bSMatthew G. Knepley 
1401b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1402846a3e8bSMatthew G. Knepley           }
14039566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1404b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1405b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v % Nv];
1406b7f6ffafSMatthew G. Knepley 
1407b7f6ffafSMatthew G. Knepley             if (v > 0) {
1408b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1409b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1410b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1411b7f6ffafSMatthew G. Knepley 
14129371c9d4SSatish Balay                 endpoints[0] = closure[v - 1];
14139371c9d4SSatish Balay                 endpoints[1] = vertex;
14149566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
141563a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
141663a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
14179566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
14181baa6e33SBarry Smith               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1419b7f6ffafSMatthew G. Knepley             }
142063a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1421b7f6ffafSMatthew G. Knepley           }
14229566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
14239566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1424846a3e8bSMatthew G. Knepley         }
1425846a3e8bSMatthew G. Knepley       }
1426b7f6ffafSMatthew G. Knepley     }
1427846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1428846a3e8bSMatthew G. Knepley       double             ccoords[3] = {0.0, 0.0, 0.0};
1429846a3e8bSMatthew G. Knepley       PetscBool          isLabeled  = PETSC_FALSE;
1430c713ec31SMatthew G. Knepley       PetscScalar       *cellCoords = NULL;
1431c713ec31SMatthew G. Knepley       const PetscScalar *array;
1432c713ec31SMatthew G. Knepley       PetscInt           numCoords, cdim, d;
1433c713ec31SMatthew G. Knepley       PetscBool          isDG;
1434846a3e8bSMatthew G. Knepley 
1435fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1436c713ec31SMatthew G. Knepley       PetscCall(DMGetCoordinateDim(dm, &cdim));
1437c713ec31SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1438c713ec31SMatthew G. Knepley       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
14399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1440c713ec31SMatthew G. Knepley       for (p = 0; p < numCoords / cdim; ++p) {
1441c713ec31SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
1442c713ec31SMatthew G. Knepley           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1443846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1444846a3e8bSMatthew G. Knepley         }
1445846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
14469371c9d4SSatish Balay         if (cdim == 3) {
14479371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
14489371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
14499371c9d4SSatish Balay           tcoords[2]    = -tmp;
14509371c9d4SSatish Balay         }
1451ad540459SPierre Jolivet         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1452846a3e8bSMatthew G. Knepley       }
1453ad540459SPierre Jolivet       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1454c713ec31SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1455c713ec31SMatthew G. Knepley       for (d = 0; d < cdim; ++d) {
14569566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1457835f2295SStefano Zampini         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]));
1458846a3e8bSMatthew G. Knepley       }
1459b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth % numColors];
1460b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
1461846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1462846a3e8bSMatthew G. Knepley         PetscInt val;
14639566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
14649371c9d4SSatish Balay         if (val >= 0) {
14659371c9d4SSatish Balay           color     = lcolors[l % numLColors];
14669371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
14679371c9d4SSatish Balay           break;
14689371c9d4SSatish Balay         }
1469846a3e8bSMatthew G. Knepley       }
1470b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
147163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1472b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
147363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
14741baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1475846a3e8bSMatthew G. Knepley     }
1476b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1477b862f699SMatthew G. Knepley       int height = 0;
1478b862f699SMatthew G. Knepley 
1479b7f6ffafSMatthew G. Knepley       color = colors[depth % numColors];
14809566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
14819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
14829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1483b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++));
14849566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1485552f7358SJed Brown 
1486b862f699SMatthew G. Knepley       if (depth > 2) {
1487b862f699SMatthew G. Knepley         color = colors[1 % numColors];
1488b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n"));
1489b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n"));
1490b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1491b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++));
1492b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1493b862f699SMatthew G. Knepley       }
1494b862f699SMatthew G. Knepley 
1495b7f6ffafSMatthew G. Knepley       color = colors[1 % numColors];
14969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
14979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
14989566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1499b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++));
15009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1501b7f6ffafSMatthew G. Knepley 
1502b7f6ffafSMatthew G. Knepley       color = colors[0 % numColors];
15039566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
15049566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
15059566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1506b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++));
15079566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1508b7f6ffafSMatthew G. Knepley 
1509b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1510b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1511b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1512b7f6ffafSMatthew G. Knepley 
15139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
15149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
151548a46eb9SPierre Jolivet         for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
15160588280cSMatthew G. Knepley       }
15170588280cSMatthew G. Knepley     }
15189566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
15199566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
15209566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
152163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
15229566063dSJacob Faibussowitsch     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
15239566063dSJacob Faibussowitsch     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
15249566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
15259566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
15269566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
15270f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
15280f7d6e4aSStefano Zampini     Vec                    cown, acown;
15290f7d6e4aSStefano Zampini     VecScatter             sct;
15300f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
15310f7d6e4aSStefano Zampini     IS                     gid, acis;
15320f7d6e4aSStefano Zampini     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
15330f7d6e4aSStefano Zampini     MPI_Group              ggroup, ngroup;
15340f7d6e4aSStefano Zampini     PetscScalar           *array, nid;
15350f7d6e4aSStefano Zampini     const PetscInt        *idxs;
15360f7d6e4aSStefano Zampini     PetscInt              *idxs2, *start, *adjacency, *work;
15370f7d6e4aSStefano Zampini     PetscInt64             lm[3], gm[3];
15380f7d6e4aSStefano Zampini     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
15390f7d6e4aSStefano Zampini     PetscMPIInt            d1, d2, rank;
15400f7d6e4aSStefano Zampini 
15419566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15429566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1543b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
15449566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
15450f7d6e4aSStefano Zampini #endif
15460f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
15479566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
15489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
15490f7d6e4aSStefano Zampini       d1 = 0;
15509566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
15510f7d6e4aSStefano Zampini       nid = d2;
15529566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
15539566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
15549566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
15550f7d6e4aSStefano Zampini     } else nid = 0.0;
15560f7d6e4aSStefano Zampini 
15570f7d6e4aSStefano Zampini     /* Get connectivity */
15589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
15599566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
15600f7d6e4aSStefano Zampini 
15610f7d6e4aSStefano Zampini     /* filter overlapped local cells */
15629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
15639566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid, &idxs));
15649566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid, &cum));
15659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &idxs2));
15660f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
15670f7d6e4aSStefano Zampini       if (idxs[c - cStart] < 0) continue;
15680f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c - cStart];
15690f7d6e4aSStefano Zampini     }
15709566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid, &idxs));
157163a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
15729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
15739566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
15740f7d6e4aSStefano Zampini 
15750f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
15769566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
15779566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
15789566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
15799566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown, &array));
15800f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
15819566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown, &array));
15829566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
15839566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
15849566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
15859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
15869566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
15879566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
15880f7d6e4aSStefano Zampini 
15890f7d6e4aSStefano Zampini     /* compute edgeCut */
15900f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
15919566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &work));
15929566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
15939566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
15949566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
15959566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown, &array));
15960f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
15970f7d6e4aSStefano Zampini       PetscInt totl;
15980f7d6e4aSStefano Zampini 
15990f7d6e4aSStefano Zampini       totl = start[c + 1] - start[c];
16009566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
16010f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
16020f7d6e4aSStefano Zampini         if (work[i] < 0) {
16030f7d6e4aSStefano Zampini           ect += 1;
16040f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
16050f7d6e4aSStefano Zampini         }
16060f7d6e4aSStefano Zampini       }
16070f7d6e4aSStefano Zampini     }
16089566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
16099566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown, &array));
16101690c2aeSBarry Smith     lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX;
16110f7d6e4aSStefano Zampini     lm[1] = -numVertices;
1612462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
1613835f2295SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0]));
16140f7d6e4aSStefano Zampini     lm[0] = ect;                     /* edgeCut */
16150f7d6e4aSStefano Zampini     lm[1] = ectn;                    /* node-aware edgeCut */
16160f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1617462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
1618835f2295SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2]));
1619b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1620835f2295SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.));
16210f7d6e4aSStefano Zampini #else
1622835f2295SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0));
16230f7d6e4aSStefano Zampini #endif
16249566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
16259566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
16269566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
16279566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1628552f7358SJed Brown   } else {
1629412e9a14SMatthew G. Knepley     const char    *name;
1630d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1631412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1632d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1633ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
16349318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1635412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1636412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1637552f7358SJed Brown 
16389566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
16399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
16409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
16419566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
16429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
16439566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
164463a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
164563a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
164663a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
16479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
1648462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
16492827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1650d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
16519566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
16529566063dSJacob Faibussowitsch     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1653412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1654412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1655412e9a14SMatthew G. Knepley 
16569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
16579566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1658412e9a14SMatthew G. Knepley       ict = ct0;
16599566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1660412e9a14SMatthew G. Knepley       ct0 = (DMPolytopeType)ict;
1661412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1662412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1663412e9a14SMatthew G. Knepley 
16649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1665412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1666412e9a14SMatthew G. Knepley         else ++Nc[1];
1667412e9a14SMatthew G. Knepley       }
1668ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
16699566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
16709566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
16719566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
167263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1673834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1674dd400576SPatrick Sanan           if (rank == 0) {
167563a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
167663a3b9bcSJacob Faibussowitsch             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
167763a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1678834065abSMatthew G. Knepley           }
1679cbb7f117SMark Adams         }
1680ca7bf7eeSMatthew G. Knepley       } else {
1681ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1682ca7bf7eeSMatthew G. Knepley 
16839371c9d4SSatish Balay         locMinMax[0] = Nc[0] + Nc[1];
16849371c9d4SSatish Balay         locMinMax[1] = Nc[0] + Nc[1];
16859566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
16869371c9d4SSatish Balay         locMinMax[0] = Nc[1];
16879371c9d4SSatish Balay         locMinMax[1] = Nc[1];
16889566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1689ca7bf7eeSMatthew G. Knepley         if (d == depth) {
16909371c9d4SSatish Balay           locMinMax[0] = gcNum;
16919371c9d4SSatish Balay           locMinMax[1] = gcNum;
16929566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1693ca7bf7eeSMatthew G. Knepley         }
169463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
16959566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
16969566063dSJacob Faibussowitsch         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
16979566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1698ca7bf7eeSMatthew G. Knepley       }
16999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1700552f7358SJed Brown     }
17019566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
17029318fe57SMatthew G. Knepley     {
17039318fe57SMatthew G. Knepley       const PetscReal *maxCell;
17049318fe57SMatthew G. Knepley       const PetscReal *L;
17056858538eSMatthew G. Knepley       PetscBool        localized;
17069318fe57SMatthew G. Knepley 
17074fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
17089566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
17096858538eSMatthew G. Knepley       if (L || localized) {
17106858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
17119566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
17126858538eSMatthew G. Knepley         if (L) {
17136858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
17149318fe57SMatthew G. Knepley           for (d = 0; d < dim; ++d) {
17156858538eSMatthew G. Knepley             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
17166858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
17179318fe57SMatthew G. Knepley           }
17186858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
17196858538eSMatthew G. Knepley         }
17206858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
17219566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
17229318fe57SMatthew G. Knepley       }
17239318fe57SMatthew G. Knepley     }
17249566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
17259566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1726a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1727a57dd577SMatthew G Knepley       DMLabel     label;
1728a57dd577SMatthew G Knepley       const char *name;
1729281879d4SJames Wright       PetscInt   *values;
1730a57dd577SMatthew G Knepley       PetscInt    numValues, v;
1731a57dd577SMatthew G Knepley 
17329566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
17339566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
17349566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
173563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1736281879d4SJames Wright 
1737281879d4SJames Wright       { // Extract array of DMLabel values so it can be sorted
1738281879d4SJames Wright         IS              is_values;
1739281879d4SJames Wright         const PetscInt *is_values_local = NULL;
1740281879d4SJames Wright 
1741281879d4SJames Wright         PetscCall(DMLabelGetValueIS(label, &is_values));
1742281879d4SJames Wright         PetscCall(ISGetIndices(is_values, &is_values_local));
1743281879d4SJames Wright         PetscCall(PetscMalloc1(numValues, &values));
1744281879d4SJames Wright         PetscCall(PetscArraycpy(values, is_values_local, numValues));
1745281879d4SJames Wright         PetscCall(PetscSortInt(numValues, values));
1746281879d4SJames Wright         PetscCall(ISRestoreIndices(is_values, &is_values_local));
1747281879d4SJames Wright         PetscCall(ISDestroy(&is_values));
1748281879d4SJames Wright       }
17499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1750a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1751a57dd577SMatthew G Knepley         PetscInt size;
1752a57dd577SMatthew G Knepley 
17539566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
17549566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
175563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1756a57dd577SMatthew G Knepley       }
17579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
17589566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1759281879d4SJames Wright       PetscCall(PetscFree(values));
1760a57dd577SMatthew G Knepley     }
1761c1cad2e7SMatthew G. Knepley     {
1762c1cad2e7SMatthew G. Knepley       char    **labelNames;
1763c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1764c1cad2e7SMatthew G. Knepley       PetscBool flg;
1765c1cad2e7SMatthew G. Knepley 
17669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
17679566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1768c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1769c1cad2e7SMatthew G. Knepley         DMLabel label;
1770c1cad2e7SMatthew G. Knepley 
17719566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1772c1cad2e7SMatthew G. Knepley         if (flg) {
17739566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
17749566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1775c1cad2e7SMatthew G. Knepley         }
17769566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1777c1cad2e7SMatthew G. Knepley       }
17789566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1779c1cad2e7SMatthew G. Knepley     }
178034aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
178134aa8a36SMatthew G. Knepley     if (dm->Nf) {
178234aa8a36SMatthew G. Knepley       PetscInt f;
178334aa8a36SMatthew G. Knepley 
178434aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
178534aa8a36SMatthew G. Knepley         const char *name;
178634aa8a36SMatthew G. Knepley 
17879566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
17889566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
17899566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
17909566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
179134aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
17929566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
17939566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
179434aa8a36SMatthew G. Knepley         } else {
17959566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
17969566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
179734aa8a36SMatthew G. Knepley         }
17989566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
179934aa8a36SMatthew G. Knepley       }
180034aa8a36SMatthew G. Knepley     }
180161f058f9SMatthew G. Knepley     DMPlexTransform tr;
180261f058f9SMatthew G. Knepley 
180361f058f9SMatthew G. Knepley     PetscCall(DMPlexGetTransform(dm, &tr));
180461f058f9SMatthew G. Knepley     if (tr) {
180561f058f9SMatthew G. Knepley       PetscCall(PetscViewerASCIIPushTab(viewer));
180661f058f9SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n"));
180761f058f9SMatthew G. Knepley       PetscCall(DMPlexTransformView(tr, viewer));
180861f058f9SMatthew G. Knepley       PetscCall(PetscViewerASCIIPopTab(viewer));
180961f058f9SMatthew G. Knepley     }
18109566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
18118e7ff633SMatthew G. Knepley     if (cdm) {
18129566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
18139f4ada15SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
18149566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
18159566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
18168e7ff633SMatthew G. Knepley     }
1817552f7358SJed Brown   }
18183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1819552f7358SJed Brown }
1820552f7358SJed Brown 
182152cfed31SJose E. Roman static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[])
1822d71ae5a4SJacob Faibussowitsch {
1823e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1824e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1825a12d352dSMatthew G. Knepley   PetscInt       cdim;
182652cfed31SJose E. Roman   int            lineColor, cellColor;
1827e5c487bfSMatthew G. Knepley 
1828e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
18299566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
18309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
18319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
183252cfed31SJose E. Roman   lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC);
183352cfed31SJose E. Roman   cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC);
1834e5c487bfSMatthew G. Knepley   switch (ct) {
1835a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1836a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1837a12d352dSMatthew G. Knepley     switch (cdim) {
18389371c9d4SSatish Balay     case 1: {
1839a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1840a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1841a12d352dSMatthew G. Knepley 
1842a36b0f0fSMatthew G. Knepley       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor));
1843a36b0f0fSMatthew G. Knepley       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor));
1844a36b0f0fSMatthew G. Knepley       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor));
18459371c9d4SSatish Balay     } break;
18469371c9d4SSatish Balay     case 2: {
1847a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1848a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1849a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1850a12d352dSMatthew G. Knepley 
1851a36b0f0fSMatthew G. Knepley       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1852a36b0f0fSMatthew G. Knepley       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor));
1853a36b0f0fSMatthew G. Knepley       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor));
18549371c9d4SSatish Balay     } break;
1855d71ae5a4SJacob Faibussowitsch     default:
1856d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1857a12d352dSMatthew G. Knepley     }
1858a12d352dSMatthew G. Knepley     break;
1859e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
1860a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1861a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1862a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor));
1863a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor));
1864e5c487bfSMatthew G. Knepley     break;
1865e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
1866a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1867a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor));
1868a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1869a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor));
1870a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor));
1871a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor));
1872e5c487bfSMatthew G. Knepley     break;
18739f4ada15SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1874a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1875a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor));
1876a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor));
1877a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor));
1878a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor));
1879a36b0f0fSMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor));
18809f4ada15SMatthew G. Knepley     break;
1881d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_FV_GHOST:
1882d71ae5a4SJacob Faibussowitsch     break;
1883d71ae5a4SJacob Faibussowitsch   default:
1884d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1885e5c487bfSMatthew G. Knepley   }
18863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1887e5c487bfSMatthew G. Knepley }
1888e5c487bfSMatthew G. Knepley 
1889c5aedaa3SMatthew G. Knepley static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1890d71ae5a4SJacob Faibussowitsch {
1891e5c487bfSMatthew G. Knepley   PetscReal   centroid[2] = {0., 0.};
1892e5c487bfSMatthew G. Knepley   PetscMPIInt rank;
18936497c311SBarry Smith   PetscMPIInt fillColor;
1894e5c487bfSMatthew G. Knepley 
1895e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
18969566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1897e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1898c5aedaa3SMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
1899c5aedaa3SMatthew G. Knepley     centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv;
1900c5aedaa3SMatthew G. Knepley     centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv;
19019371c9d4SSatish Balay   }
1902c5aedaa3SMatthew G. Knepley   for (PetscInt e = 0; e < Nv; ++e) {
1903e5c487bfSMatthew G. Knepley     refCoords[0] = refVertices[e * 2 + 0];
1904e5c487bfSMatthew G. Knepley     refCoords[1] = refVertices[e * 2 + 1];
1905c5aedaa3SMatthew G. Knepley     for (PetscInt d = 1; d <= edgeDiv; ++d) {
1906c5aedaa3SMatthew G. Knepley       refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv;
1907c5aedaa3SMatthew G. Knepley       refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv;
1908e5c487bfSMatthew G. Knepley     }
19099566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1910c5aedaa3SMatthew G. Knepley     for (PetscInt d = 0; d < edgeDiv; ++d) {
19119566063dSJacob 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));
19129566063dSJacob 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));
1913e5c487bfSMatthew G. Knepley     }
1914e5c487bfSMatthew G. Knepley   }
1915c5aedaa3SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1916c5aedaa3SMatthew G. Knepley }
1917c5aedaa3SMatthew G. Knepley 
1918c5aedaa3SMatthew G. Knepley static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1919c5aedaa3SMatthew G. Knepley {
1920c5aedaa3SMatthew G. Knepley   DMPolytopeType ct;
1921c5aedaa3SMatthew G. Knepley 
1922c5aedaa3SMatthew G. Knepley   PetscFunctionBegin;
1923c5aedaa3SMatthew G. Knepley   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1924c5aedaa3SMatthew G. Knepley   switch (ct) {
1925c5aedaa3SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE: {
1926c5aedaa3SMatthew G. Knepley     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1927c5aedaa3SMatthew G. Knepley 
1928c5aedaa3SMatthew G. Knepley     PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1929c5aedaa3SMatthew G. Knepley   } break;
1930c5aedaa3SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL: {
1931c5aedaa3SMatthew G. Knepley     PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.};
1932c5aedaa3SMatthew G. Knepley 
1933c5aedaa3SMatthew G. Knepley     PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords));
19349371c9d4SSatish Balay   } break;
1935d71ae5a4SJacob Faibussowitsch   default:
1936d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1937e5c487bfSMatthew G. Knepley   }
19383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1939e5c487bfSMatthew G. Knepley }
1940e5c487bfSMatthew G. Knepley 
1941d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1942d71ae5a4SJacob Faibussowitsch {
1943e412dcbdSMatthew G. Knepley   PetscDraw    draw;
1944e412dcbdSMatthew G. Knepley   DM           cdm;
1945e412dcbdSMatthew G. Knepley   PetscSection coordSection;
1946e412dcbdSMatthew G. Knepley   Vec          coordinates;
1947c9c77995SMatthew G. Knepley   PetscReal    xyl[3], xyr[3];
1948e5c487bfSMatthew G. Knepley   PetscReal   *refCoords, *edgeCoords;
1949c5aedaa3SMatthew G. Knepley   PetscBool    isnull, drawAffine;
1950a36b0f0fSMatthew G. Knepley   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE;
1951e412dcbdSMatthew G. Knepley 
1952e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
19539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
195463a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1955c5aedaa3SMatthew G. Knepley   PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree));
1956c5aedaa3SMatthew G. Knepley   drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE;
1957c5aedaa3SMatthew G. Knepley   edgeDiv    = cDegree + 1;
1958a36b0f0fSMatthew G. Knepley   PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL));
1959a36b0f0fSMatthew G. Knepley   PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL));
19609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
19619566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
19629566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
19639566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
19649566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
19659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
19669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1967e412dcbdSMatthew G. Knepley 
19689566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
19699566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
19703ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
19719566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1972e412dcbdSMatthew G. Knepley 
1973c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
19749566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
19759566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1976e412dcbdSMatthew G. Knepley 
1977cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1978cf3064d3SMatthew G. Knepley     PetscScalar       *coords = NULL;
1979c9c77995SMatthew G. Knepley     const PetscScalar *coords_arr;
1980ba2698f1SMatthew G. Knepley     PetscInt           numCoords;
1981c9c77995SMatthew G. Knepley     PetscBool          isDG;
1982cf3064d3SMatthew G. Knepley 
1983c9c77995SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1984a36b0f0fSMatthew G. Knepley     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords));
19851baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1986c9c77995SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1987cf3064d3SMatthew G. Knepley   }
19889566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
19899566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
19909566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
19919566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
19923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1993e412dcbdSMatthew G. Knepley }
1994e412dcbdSMatthew G. Knepley 
1995e44f6aebSMatthew G. Knepley static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1996e44f6aebSMatthew G. Knepley {
1997e44f6aebSMatthew G. Knepley   DM           odm = dm, rdm = dm, cdm;
1998e44f6aebSMatthew G. Knepley   PetscFE      fe;
1999e44f6aebSMatthew G. Knepley   PetscSpace   sp;
2000e44f6aebSMatthew G. Knepley   PetscClassId id;
2001e44f6aebSMatthew G. Knepley   PetscInt     degree;
2002e44f6aebSMatthew G. Knepley   PetscBool    hoView = PETSC_TRUE;
2003e44f6aebSMatthew G. Knepley 
2004e44f6aebSMatthew G. Knepley   PetscFunctionBegin;
2005e44f6aebSMatthew G. Knepley   PetscObjectOptionsBegin((PetscObject)dm);
2006e44f6aebSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
2007e44f6aebSMatthew G. Knepley   PetscOptionsEnd();
2008e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)dm));
2009e44f6aebSMatthew G. Knepley   *hdm = dm;
2010e44f6aebSMatthew G. Knepley   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
2011e44f6aebSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
2012e44f6aebSMatthew G. Knepley   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
2013e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
2014e44f6aebSMatthew G. Knepley   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
2015e44f6aebSMatthew G. Knepley   PetscCall(PetscFEGetBasisSpace(fe, &sp));
2016e44f6aebSMatthew G. Knepley   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
2017e44f6aebSMatthew G. Knepley   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
2018e44f6aebSMatthew G. Knepley     DM  cdm, rcdm;
2019e44f6aebSMatthew G. Knepley     Mat In;
2020e44f6aebSMatthew G. Knepley     Vec cl, rcl;
2021e44f6aebSMatthew G. Knepley 
2022e44f6aebSMatthew G. Knepley     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
2023e65c294aSksagiyam     PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE));
2024e44f6aebSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
2025e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(odm, &cdm));
2026e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
2027e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(odm, &cl));
2028e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
2029e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoarseDM(rcdm, cdm));
2030e44f6aebSMatthew G. Knepley     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
2031e44f6aebSMatthew G. Knepley     PetscCall(MatMult(In, cl, rcl));
2032e44f6aebSMatthew G. Knepley     PetscCall(MatDestroy(&In));
2033e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
2034e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&odm));
2035e44f6aebSMatthew G. Knepley     odm = rdm;
2036e44f6aebSMatthew G. Knepley   }
2037e44f6aebSMatthew G. Knepley   *hdm = rdm;
2038e44f6aebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2039e44f6aebSMatthew G. Knepley }
2040e44f6aebSMatthew G. Knepley 
20411e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
20421e50132fSMatthew G. Knepley   #include <exodusII.h>
20431e50132fSMatthew G. Knepley #endif
20441e50132fSMatthew G. Knepley 
2045d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
2046d71ae5a4SJacob Faibussowitsch {
20479f196a02SMartin Diehl   PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython;
2048002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
2049552f7358SJed Brown 
2050552f7358SJed Brown   PetscFunctionBegin;
2051552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2052552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20539f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
20549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
20559566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20569566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
20579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
20589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
20595f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
206022d6dc08SStefano Zampini   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
20619f196a02SMartin Diehl   if (isascii) {
20628135c375SStefano Zampini     PetscViewerFormat format;
20639566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20641baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
20651baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
2066c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
2067c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
20689566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
2069c6ccd67eSMatthew G. Knepley #else
2070c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2071552f7358SJed Brown #endif
2072e412dcbdSMatthew G. Knepley   } else if (isvtk) {
20739566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
2074e412dcbdSMatthew G. Knepley   } else if (isdraw) {
2075e44f6aebSMatthew G. Knepley     DM hdm;
2076e44f6aebSMatthew G. Knepley 
2077e44f6aebSMatthew G. Knepley     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
2078e44f6aebSMatthew G. Knepley     PetscCall(DMPlexView_Draw(hdm, viewer));
2079e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&hdm));
20808135c375SStefano Zampini   } else if (isglvis) {
20819566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
20821e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
20831e50132fSMatthew G. Knepley   } else if (isexodus) {
20846823f3c5SBlaise Bourdin     /*
2085caff39ffSPierre Jolivet       ExodusII requires that all sets be part of exactly one cell set.
20866823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
2087da81f932SPierre Jolivet       with ID 1, containing all cells.
20886823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
20896823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
20906823f3c5SBlaise Bourdin     */
20916823f3c5SBlaise Bourdin     PetscInt numCS;
20929566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
20936823f3c5SBlaise Bourdin     if (!numCS) {
20941e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
20959566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
20969566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
20979566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
20986823f3c5SBlaise Bourdin     }
20999566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
21001e50132fSMatthew G. Knepley #endif
21015f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
21025f34f2dcSJed Brown   } else if (iscgns) {
21035f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
21045f34f2dcSJed Brown #endif
210522d6dc08SStefano Zampini   } else if (ispython) {
210622d6dc08SStefano Zampini     PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm));
21071baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
2108cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
21099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
2110cb3ba0daSMatthew G. Knepley   if (flg) {
2111cb3ba0daSMatthew G. Knepley     Vec ranks;
21129566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
21139566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
21149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
2115cb3ba0daSMatthew G. Knepley   }
2116002a2709SMatthew G. Knepley   /* Optionally view a label */
21179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
2118002a2709SMatthew G. Knepley   if (flg) {
2119002a2709SMatthew G. Knepley     DMLabel label;
2120002a2709SMatthew G. Knepley     Vec     val;
2121002a2709SMatthew G. Knepley 
21229566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
212328b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
21249566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
21259566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
21269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
2127002a2709SMatthew G. Knepley   }
21283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2129552f7358SJed Brown }
2130552f7358SJed Brown 
21317f96f51bSksagiyam /*@
2132a1cb98faSBarry Smith   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
21337f96f51bSksagiyam 
213420f4b53cSBarry Smith   Collective
21357f96f51bSksagiyam 
21367f96f51bSksagiyam   Input Parameters:
2137a1cb98faSBarry Smith + dm     - The `DM` whose topology is to be saved
2138a1cb98faSBarry Smith - viewer - The `PetscViewer` to save it in
21397f96f51bSksagiyam 
21407f96f51bSksagiyam   Level: advanced
21417f96f51bSksagiyam 
21421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
21437f96f51bSksagiyam @*/
2144d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2145d71ae5a4SJacob Faibussowitsch {
21467f96f51bSksagiyam   PetscBool ishdf5;
21477f96f51bSksagiyam 
21487f96f51bSksagiyam   PetscFunctionBegin;
21497f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21507f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21529566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
21537f96f51bSksagiyam   if (ishdf5) {
21547f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
21557f96f51bSksagiyam     IS                globalPointNumbering;
2156966bd95aSPierre Jolivet     PetscViewerFormat format;
21577f96f51bSksagiyam 
2158966bd95aSPierre Jolivet     PetscCall(PetscViewerGetFormat(viewer, &format));
2159966bd95aSPierre Jolivet     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
21609566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
21619566063dSJacob Faibussowitsch     PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
21629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&globalPointNumbering));
21637f96f51bSksagiyam #else
21647f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
21657f96f51bSksagiyam #endif
21667f96f51bSksagiyam   }
21679566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
21683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21697f96f51bSksagiyam }
21707f96f51bSksagiyam 
217177b8e257Sksagiyam /*@
2172a1cb98faSBarry Smith   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
217377b8e257Sksagiyam 
217420f4b53cSBarry Smith   Collective
217577b8e257Sksagiyam 
217677b8e257Sksagiyam   Input Parameters:
2177a1cb98faSBarry Smith + dm     - The `DM` whose coordinates are to be saved
2178a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
217977b8e257Sksagiyam 
218077b8e257Sksagiyam   Level: advanced
218177b8e257Sksagiyam 
21821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
218377b8e257Sksagiyam @*/
2184d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2185d71ae5a4SJacob Faibussowitsch {
218677b8e257Sksagiyam   PetscBool ishdf5;
218777b8e257Sksagiyam 
218877b8e257Sksagiyam   PetscFunctionBegin;
218977b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
219077b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21919566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
219377b8e257Sksagiyam   if (ishdf5) {
219477b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
219577b8e257Sksagiyam     PetscViewerFormat format;
2196966bd95aSPierre Jolivet 
21979566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2198966bd95aSPierre Jolivet     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
21999566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
220077b8e257Sksagiyam #else
220177b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
220277b8e257Sksagiyam #endif
220377b8e257Sksagiyam   }
22049566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
22053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
220677b8e257Sksagiyam }
220777b8e257Sksagiyam 
2208bd6565f1Sksagiyam /*@
2209a1cb98faSBarry Smith   DMPlexLabelsView - Saves `DMPLEX` labels into a file
2210bd6565f1Sksagiyam 
221120f4b53cSBarry Smith   Collective
2212bd6565f1Sksagiyam 
2213bd6565f1Sksagiyam   Input Parameters:
2214a1cb98faSBarry Smith + dm     - The `DM` whose labels are to be saved
2215a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
2216bd6565f1Sksagiyam 
2217bd6565f1Sksagiyam   Level: advanced
2218bd6565f1Sksagiyam 
22191cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2220bd6565f1Sksagiyam @*/
2221d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2222d71ae5a4SJacob Faibussowitsch {
2223bd6565f1Sksagiyam   PetscBool ishdf5;
2224bd6565f1Sksagiyam 
2225bd6565f1Sksagiyam   PetscFunctionBegin;
2226bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2227bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2230bd6565f1Sksagiyam   if (ishdf5) {
2231bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
2232bd6565f1Sksagiyam     IS                globalPointNumbering;
2233bd6565f1Sksagiyam     PetscViewerFormat format;
2234bd6565f1Sksagiyam 
22359566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2236966bd95aSPierre Jolivet     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
22379566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
22389566063dSJacob Faibussowitsch     PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
22399566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&globalPointNumbering));
2240bd6565f1Sksagiyam #else
2241bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2242bd6565f1Sksagiyam #endif
2243bd6565f1Sksagiyam   }
22449566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
22453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2246bd6565f1Sksagiyam }
2247bd6565f1Sksagiyam 
2248021affd3Sksagiyam /*@
2249a1cb98faSBarry Smith   DMPlexSectionView - Saves a section associated with a `DMPLEX`
2250021affd3Sksagiyam 
225120f4b53cSBarry Smith   Collective
2252021affd3Sksagiyam 
2253021affd3Sksagiyam   Input Parameters:
2254a1cb98faSBarry Smith + dm        - The `DM` that contains the topology on which the section to be saved is defined
2255a1cb98faSBarry Smith . viewer    - The `PetscViewer` for saving
22560318f8a0SStefano Zampini - sectiondm - The `DM` that contains the section to be saved, can be `NULL`
2257021affd3Sksagiyam 
2258021affd3Sksagiyam   Level: advanced
2259021affd3Sksagiyam 
2260021affd3Sksagiyam   Notes:
2261420bcc1bSBarry Smith   This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points.
2262021affd3Sksagiyam 
22630318f8a0SStefano Zampini   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2264021affd3Sksagiyam 
22651cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2266021affd3Sksagiyam @*/
2267d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2268d71ae5a4SJacob Faibussowitsch {
2269021affd3Sksagiyam   PetscBool ishdf5;
2270021affd3Sksagiyam 
2271021affd3Sksagiyam   PetscFunctionBegin;
2272021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2273021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22740318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
2275021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
22769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2278021affd3Sksagiyam   if (ishdf5) {
2279021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
22809566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2281021affd3Sksagiyam #else
2282021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2283021affd3Sksagiyam #endif
2284021affd3Sksagiyam   }
22859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
22863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2287021affd3Sksagiyam }
2288021affd3Sksagiyam 
22893e97647fSksagiyam /*@
22903e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
22913e97647fSksagiyam 
229220f4b53cSBarry Smith   Collective
22933e97647fSksagiyam 
22943e97647fSksagiyam   Input Parameters:
2295a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2296a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
22970318f8a0SStefano Zampini . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
22983e97647fSksagiyam - vec       - The global vector to be saved
22993e97647fSksagiyam 
23003e97647fSksagiyam   Level: advanced
23013e97647fSksagiyam 
23023e97647fSksagiyam   Notes:
23030318f8a0SStefano Zampini   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
23043e97647fSksagiyam 
230560225df5SJacob Faibussowitsch   Calling sequence:
2306a1cb98faSBarry Smith .vb
2307a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2308a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2309a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2310a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2311a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2312a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2313a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2314a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2315a1cb98faSBarry Smith        PetscSectionSetUp(section);
2316a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2317a1cb98faSBarry Smith        PetscSectionDestroy(&section);
2318a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2319a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2320a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2321a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2322a1cb98faSBarry Smith        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2323a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2324a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2325a1cb98faSBarry Smith        DMDestroy(&dm);
2326a1cb98faSBarry Smith .ve
23273e97647fSksagiyam 
23281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
23293e97647fSksagiyam @*/
2330d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2331d71ae5a4SJacob Faibussowitsch {
23323e97647fSksagiyam   PetscBool ishdf5;
23333e97647fSksagiyam 
23343e97647fSksagiyam   PetscFunctionBegin;
23353e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23363e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23370318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
23383e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
23393e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
23403e97647fSksagiyam   /* Check consistency */
23413e97647fSksagiyam   {
23423e97647fSksagiyam     PetscSection section;
23433e97647fSksagiyam     PetscBool    includesConstraints;
23443e97647fSksagiyam     PetscInt     m, m1;
23453e97647fSksagiyam 
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);
23523e97647fSksagiyam   }
23539566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
23553e97647fSksagiyam   if (ishdf5) {
23563e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
23579566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
23583e97647fSksagiyam #else
23593e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23603e97647fSksagiyam #endif
23613e97647fSksagiyam   }
23629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
23633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23643e97647fSksagiyam }
23653e97647fSksagiyam 
23663e97647fSksagiyam /*@
23673e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
23683e97647fSksagiyam 
236920f4b53cSBarry Smith   Collective
23703e97647fSksagiyam 
23713e97647fSksagiyam   Input Parameters:
2372a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2373a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
23740318f8a0SStefano Zampini . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL`
23753e97647fSksagiyam - vec       - The local vector to be saved
23763e97647fSksagiyam 
23773e97647fSksagiyam   Level: advanced
23783e97647fSksagiyam 
2379a1cb98faSBarry Smith   Note:
23800318f8a0SStefano Zampini   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
23813e97647fSksagiyam 
238260225df5SJacob Faibussowitsch   Calling sequence:
2383a1cb98faSBarry Smith .vb
2384a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2385a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2386a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2387a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2388a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2389a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2390a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2391a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2392a1cb98faSBarry Smith        PetscSectionSetUp(section);
2393a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2394a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2395a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2396a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2397a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2398a1cb98faSBarry Smith        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2399a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2400a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2401a1cb98faSBarry Smith        DMDestroy(&dm);
2402a1cb98faSBarry Smith .ve
24033e97647fSksagiyam 
24041cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
24053e97647fSksagiyam @*/
2406d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2407d71ae5a4SJacob Faibussowitsch {
24083e97647fSksagiyam   PetscBool ishdf5;
24093e97647fSksagiyam 
24103e97647fSksagiyam   PetscFunctionBegin;
24113e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24123e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24130318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
24143e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24153e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
24163e97647fSksagiyam   /* Check consistency */
24173e97647fSksagiyam   {
24183e97647fSksagiyam     PetscSection section;
24193e97647fSksagiyam     PetscBool    includesConstraints;
24203e97647fSksagiyam     PetscInt     m, m1;
24213e97647fSksagiyam 
24229566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24239566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
24249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24259566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24269566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
242763a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
24283e97647fSksagiyam   }
24299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24309566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
24313e97647fSksagiyam   if (ishdf5) {
24323e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
24339566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
24343e97647fSksagiyam #else
24353e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24363e97647fSksagiyam #endif
24373e97647fSksagiyam   }
24389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
24393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24403e97647fSksagiyam }
24413e97647fSksagiyam 
2442d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2443d71ae5a4SJacob Faibussowitsch {
2444d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
24452c40f234SMatthew G. Knepley 
24462c40f234SMatthew G. Knepley   PetscFunctionBegin;
24472c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24482c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2450d4f5a9a0SVaclav Hapla   if (ishdf5) {
24512c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
24529c48423bSVaclav Hapla     PetscViewerFormat format;
24539566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
24549c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
24559566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2456509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24579566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
245898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
24593ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
24602c40f234SMatthew G. Knepley #else
24612c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2462552f7358SJed Brown #endif
246398921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2464552f7358SJed Brown }
2465552f7358SJed Brown 
2466ea8e1828Sksagiyam /*@
2467a1cb98faSBarry Smith   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2468ea8e1828Sksagiyam 
246920f4b53cSBarry Smith   Collective
2470ea8e1828Sksagiyam 
2471ea8e1828Sksagiyam   Input Parameters:
2472a1cb98faSBarry Smith + dm     - The `DM` into which the topology is loaded
2473a1cb98faSBarry Smith - viewer - The `PetscViewer` for the saved topology
2474ea8e1828Sksagiyam 
24752fe279fdSBarry Smith   Output Parameter:
24762c9a7b26SBarry Smith . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points;
24772c9a7b26SBarry Smith   `NULL` if unneeded
2478dec9e869Sksagiyam 
2479ea8e1828Sksagiyam   Level: advanced
2480ea8e1828Sksagiyam 
24811cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2482a1cb98faSBarry Smith           `PetscViewer`, `PetscSF`
2483ea8e1828Sksagiyam @*/
2484d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2485d71ae5a4SJacob Faibussowitsch {
2486ea8e1828Sksagiyam   PetscBool ishdf5;
2487ea8e1828Sksagiyam 
2488ea8e1828Sksagiyam   PetscFunctionBegin;
2489ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2490ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24914f572ea9SToby Isaac   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
24929566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24939566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2494ea8e1828Sksagiyam   if (ishdf5) {
2495ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2496ea8e1828Sksagiyam     PetscViewerFormat format;
2497966bd95aSPierre Jolivet 
24989566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2499966bd95aSPierre Jolivet     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
25009566063dSJacob Faibussowitsch     PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2501ea8e1828Sksagiyam #else
2502ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2503ea8e1828Sksagiyam #endif
2504ea8e1828Sksagiyam   }
25059566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
25063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2507ea8e1828Sksagiyam }
2508ea8e1828Sksagiyam 
25093e701f1cSksagiyam /*@
2510a1cb98faSBarry Smith   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
25113e701f1cSksagiyam 
251220f4b53cSBarry Smith   Collective
25133e701f1cSksagiyam 
25143e701f1cSksagiyam   Input Parameters:
2515a1cb98faSBarry Smith + dm                   - The `DM` into which the coordinates are loaded
2516a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved coordinates
2517a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
25183e701f1cSksagiyam 
25193e701f1cSksagiyam   Level: advanced
25203e701f1cSksagiyam 
25211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2522a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
25233e701f1cSksagiyam @*/
2524d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2525d71ae5a4SJacob Faibussowitsch {
25263e701f1cSksagiyam   PetscBool ishdf5;
25273e701f1cSksagiyam 
25283e701f1cSksagiyam   PetscFunctionBegin;
25293e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25303e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2531c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
25329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
25343e701f1cSksagiyam   if (ishdf5) {
25353e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
25363e701f1cSksagiyam     PetscViewerFormat format;
2537966bd95aSPierre Jolivet 
25389566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2539966bd95aSPierre Jolivet     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
25409566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
25413e701f1cSksagiyam #else
25423e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
25433e701f1cSksagiyam #endif
25443e701f1cSksagiyam   }
25459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
25463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25473e701f1cSksagiyam }
25483e701f1cSksagiyam 
2549b08ad5deSksagiyam /*@
2550a1cb98faSBarry Smith   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2551b08ad5deSksagiyam 
255220f4b53cSBarry Smith   Collective
2553b08ad5deSksagiyam 
2554b08ad5deSksagiyam   Input Parameters:
2555a1cb98faSBarry Smith + dm                   - The `DM` into which the labels are loaded
2556a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved labels
255720f4b53cSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2558b08ad5deSksagiyam 
2559b08ad5deSksagiyam   Level: advanced
2560b08ad5deSksagiyam 
2561a1cb98faSBarry Smith   Note:
2562dc9a610eSPierre Jolivet   The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs.
2563e6368b79SVaclav Hapla 
25641cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2565a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
2566b08ad5deSksagiyam @*/
2567d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2568d71ae5a4SJacob Faibussowitsch {
2569b08ad5deSksagiyam   PetscBool ishdf5;
2570b08ad5deSksagiyam 
2571b08ad5deSksagiyam   PetscFunctionBegin;
2572b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2573b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2574e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
25759566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2577b08ad5deSksagiyam   if (ishdf5) {
2578b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2579b08ad5deSksagiyam     PetscViewerFormat format;
2580b08ad5deSksagiyam 
25819566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2582966bd95aSPierre Jolivet     PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
25839566063dSJacob Faibussowitsch     PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2584b08ad5deSksagiyam #else
2585b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2586b08ad5deSksagiyam #endif
2587b08ad5deSksagiyam   }
25889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
25893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2590b08ad5deSksagiyam }
2591b08ad5deSksagiyam 
2592f84dd6b4Sksagiyam /*@
2593a1cb98faSBarry Smith   DMPlexSectionLoad - Loads section into a `DMPLEX`
2594f84dd6b4Sksagiyam 
259520f4b53cSBarry Smith   Collective
2596f84dd6b4Sksagiyam 
2597f84dd6b4Sksagiyam   Input Parameters:
2598a1cb98faSBarry Smith + dm                   - The `DM` that represents the topology
2599a1cb98faSBarry Smith . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
26000318f8a0SStefano Zampini . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL`
2601a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2602f84dd6b4Sksagiyam 
2603a4e35b19SJacob Faibussowitsch   Output Parameters:
260420f4b53cSBarry Smith + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed)
260520f4b53cSBarry Smith - localDofSF  - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed)
2606f84dd6b4Sksagiyam 
2607f84dd6b4Sksagiyam   Level: advanced
2608f84dd6b4Sksagiyam 
2609f84dd6b4Sksagiyam   Notes:
261020f4b53cSBarry Smith   This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points.
2611f84dd6b4Sksagiyam 
26120318f8a0SStefano Zampini   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2613f84dd6b4Sksagiyam 
261420f4b53cSBarry Smith   The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section.
2615f84dd6b4Sksagiyam 
2616f84dd6b4Sksagiyam   Example using 2 processes:
2617a1cb98faSBarry Smith .vb
2618a1cb98faSBarry Smith   NX (number of points on dm): 4
2619a1cb98faSBarry Smith   sectionA                   : the on-disk section
2620a1cb98faSBarry Smith   vecA                       : a vector associated with sectionA
2621a1cb98faSBarry Smith   sectionB                   : sectiondm's local section constructed in this function
2622a1cb98faSBarry Smith   vecB (local)               : a vector associated with sectiondm's local section
2623a1cb98faSBarry Smith   vecB (global)              : a vector associated with sectiondm's global section
2624f84dd6b4Sksagiyam 
2625a1cb98faSBarry Smith                                      rank 0    rank 1
2626a1cb98faSBarry Smith   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2627a1cb98faSBarry Smith   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2628a1cb98faSBarry Smith   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2629a1cb98faSBarry Smith   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2630a1cb98faSBarry Smith   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2631a1cb98faSBarry Smith   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2632a1cb98faSBarry Smith   sectionB->atlasDof             :     1 0 1 | 1 3
2633a1cb98faSBarry Smith   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2634a1cb98faSBarry Smith   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2635a1cb98faSBarry Smith   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2636a1cb98faSBarry Smith .ve
2637a1cb98faSBarry Smith   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2638a1cb98faSBarry Smith 
26391cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2640f84dd6b4Sksagiyam @*/
2641ce78bad3SBarry Smith PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF)
2642d71ae5a4SJacob Faibussowitsch {
2643f84dd6b4Sksagiyam   PetscBool ishdf5;
2644f84dd6b4Sksagiyam 
2645f84dd6b4Sksagiyam   PetscFunctionBegin;
2646f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2647f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
26480318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
2649f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2650f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
26514f572ea9SToby Isaac   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
26524f572ea9SToby Isaac   if (localDofSF) PetscAssertPointer(localDofSF, 6);
26539566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
26549566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2655f84dd6b4Sksagiyam   if (ishdf5) {
2656f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
26579566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2658f84dd6b4Sksagiyam #else
2659f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2660f84dd6b4Sksagiyam #endif
2661f84dd6b4Sksagiyam   }
26629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
26633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2664f84dd6b4Sksagiyam }
2665f84dd6b4Sksagiyam 
26668be3dfe1Sksagiyam /*@
26678be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
26688be3dfe1Sksagiyam 
266920f4b53cSBarry Smith   Collective
26708be3dfe1Sksagiyam 
26718be3dfe1Sksagiyam   Input Parameters:
2672a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2673a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
26740318f8a0SStefano Zampini . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2675a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
26768be3dfe1Sksagiyam - vec       - The global vector to set values of
26778be3dfe1Sksagiyam 
26788be3dfe1Sksagiyam   Level: advanced
26798be3dfe1Sksagiyam 
26808be3dfe1Sksagiyam   Notes:
26810318f8a0SStefano Zampini   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
26828be3dfe1Sksagiyam 
268360225df5SJacob Faibussowitsch   Calling sequence:
2684a1cb98faSBarry Smith .vb
2685a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2686a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2687a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2688a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2689a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2690a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2691a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2692a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2693a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2694a1cb98faSBarry Smith        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2695a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2696a1cb98faSBarry Smith        PetscSFDestroy(&gsf);
2697a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2698a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2699a1cb98faSBarry Smith        DMDestroy(&dm);
2700a1cb98faSBarry Smith .ve
27018be3dfe1Sksagiyam 
27021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2703a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
27048be3dfe1Sksagiyam @*/
2705d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2706d71ae5a4SJacob Faibussowitsch {
27078be3dfe1Sksagiyam   PetscBool ishdf5;
27088be3dfe1Sksagiyam 
27098be3dfe1Sksagiyam   PetscFunctionBegin;
27108be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27118be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
27120318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
27138be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
27148be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
27158be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
27168be3dfe1Sksagiyam   /* Check consistency */
27178be3dfe1Sksagiyam   {
27188be3dfe1Sksagiyam     PetscSection section;
27198be3dfe1Sksagiyam     PetscBool    includesConstraints;
27208be3dfe1Sksagiyam     PetscInt     m, m1;
27218be3dfe1Sksagiyam 
27229566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
27239566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
27249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
27259566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
27269566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
272763a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
27288be3dfe1Sksagiyam   }
27299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
27309566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
27318be3dfe1Sksagiyam   if (ishdf5) {
27328be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
27339566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
27348be3dfe1Sksagiyam #else
27358be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
27368be3dfe1Sksagiyam #endif
27378be3dfe1Sksagiyam   }
27389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
27393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27408be3dfe1Sksagiyam }
27418be3dfe1Sksagiyam 
27428be3dfe1Sksagiyam /*@
27438be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
27448be3dfe1Sksagiyam 
274520f4b53cSBarry Smith   Collective
27468be3dfe1Sksagiyam 
27478be3dfe1Sksagiyam   Input Parameters:
2748a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2749a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
27500318f8a0SStefano Zampini . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL`
2751a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
27528be3dfe1Sksagiyam - vec       - The local vector to set values of
27538be3dfe1Sksagiyam 
27548be3dfe1Sksagiyam   Level: advanced
27558be3dfe1Sksagiyam 
27568be3dfe1Sksagiyam   Notes:
27570318f8a0SStefano Zampini   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
27588be3dfe1Sksagiyam 
275960225df5SJacob Faibussowitsch   Calling sequence:
2760a1cb98faSBarry Smith .vb
2761a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2762a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2763a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2764a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2765a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2766a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2767a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2768a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2769a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2770a1cb98faSBarry Smith        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2771a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2772a1cb98faSBarry Smith        PetscSFDestroy(&lsf);
2773a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2774a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2775a1cb98faSBarry Smith        DMDestroy(&dm);
2776a1cb98faSBarry Smith .ve
27778be3dfe1Sksagiyam 
27781cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2779a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
27808be3dfe1Sksagiyam @*/
2781d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2782d71ae5a4SJacob Faibussowitsch {
27838be3dfe1Sksagiyam   PetscBool ishdf5;
27848be3dfe1Sksagiyam 
27858be3dfe1Sksagiyam   PetscFunctionBegin;
27868be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27878be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
27880318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
27898be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
27908be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
27918be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
27928be3dfe1Sksagiyam   /* Check consistency */
27938be3dfe1Sksagiyam   {
27948be3dfe1Sksagiyam     PetscSection section;
27958be3dfe1Sksagiyam     PetscBool    includesConstraints;
27968be3dfe1Sksagiyam     PetscInt     m, m1;
27978be3dfe1Sksagiyam 
27989566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
27999566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
28009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
28019566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
28029566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
280363a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
28048be3dfe1Sksagiyam   }
28059566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
28069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
28078be3dfe1Sksagiyam   if (ishdf5) {
28088be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
28099566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
28108be3dfe1Sksagiyam #else
28118be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
28128be3dfe1Sksagiyam #endif
28138be3dfe1Sksagiyam   }
28149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
28153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28168be3dfe1Sksagiyam }
28178be3dfe1Sksagiyam 
2818d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2819d71ae5a4SJacob Faibussowitsch {
2820552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2821552f7358SJed Brown 
2822552f7358SJed Brown   PetscFunctionBegin;
28239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
28249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
282501468941SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
282601468941SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL));
28279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
28289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
28292e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
28302e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
28312e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
28322e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
28336bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
28346bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2835adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL));
2836adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL));
2837adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL));
2838adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL));
2839c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2840c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2841d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2842d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
28435f06a3ddSJed Brown   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
28443ba16761SJacob Faibussowitsch   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
28459566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
28469566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
28479566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
28489566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
28499566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
28509566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
285121027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
28529f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
28539566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
28549566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
28559566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
28561d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
28579566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
28589566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
28599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
28609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
28619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
28621fca310dSJames Wright   if (mesh->periodic.face_sfs) {
28631fca310dSJames Wright     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i]));
28641fca310dSJames Wright     PetscCall(PetscFree(mesh->periodic.face_sfs));
28651fca310dSJames Wright   }
28666725e60dSJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2867b83f62b0SJames Wright   if (mesh->periodic.periodic_points) {
2868b83f62b0SJames Wright     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i]));
2869b83f62b0SJames Wright     PetscCall(PetscFree(mesh->periodic.periodic_points));
2870b83f62b0SJames Wright   }
28711fca310dSJames Wright   if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform));
28729566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
28739566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
28749566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
28759566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
28769566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
28779566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
28789566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
28799566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
28809566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
28819566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
28829566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2883c29ce622SStefano Zampini   if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm));
288461f058f9SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->transform));
2885552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
28869566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
28873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2888552f7358SJed Brown }
2889552f7358SJed Brown 
2890d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2891d71ae5a4SJacob Faibussowitsch {
2892d02c7345SMatthew G. Knepley   PetscSection           sectionGlobal, sectionLocal;
2893acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
28949fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2895837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2896b412c318SBarry Smith   MatType                mtype;
28971428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2898552f7358SJed Brown 
2899552f7358SJed Brown   PetscFunctionBegin;
29009566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2901b412c318SBarry Smith   mtype = dm->mattype;
2902d02c7345SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &sectionLocal));
29039566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
29049566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
29059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
29069fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
29079566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
29089566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
29099566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
29109566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
29119566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2912acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
29139566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
29149566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
29159566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
29169566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
29179566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
29189566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
29199566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
29209566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2921552f7358SJed Brown   if (!isShell) {
29221c6742e7SMatthew G. Knepley     // There are three states with pblocks, since block starts can have no dofs:
29231c6742e7SMatthew G. Knepley     // UNKNOWN) New Block:   An open block has been signalled by pblocks[p] == 1
29241c6742e7SMatthew G. Knepley     // TRUE)    Block Start: The first entry in a block has been added
29251c6742e7SMatthew G. Knepley     // FALSE)   Block Add:   An additional block entry has been added, since pblocks[p] == 0
29261c6742e7SMatthew G. Knepley     PetscBT         blst;
29271c6742e7SMatthew G. Knepley     PetscBool3      bstate     = PETSC_BOOL3_UNKNOWN;
2928837628f4SStefano Zampini     PetscBool       fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
29291c6742e7SMatthew G. Knepley     const PetscInt *perm       = NULL;
29309fca9976SJed Brown     PetscInt       *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
29311c6742e7SMatthew G. Knepley     PetscInt        pStart, pEnd, dof, cdof, num_fields;
2932552f7358SJed Brown 
29339566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
29341c6742e7SMatthew G. Knepley     PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst));
29351c6742e7SMatthew G. Knepley     if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm));
29369fca9976SJed Brown 
29379fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
29389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2939863027abSJed Brown     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
29401c6742e7SMatthew G. Knepley     // We need to process in the permuted order to get block sizes right
29411c6742e7SMatthew G. Knepley     for (PetscInt point = pStart; point < pEnd; ++point) {
29421c6742e7SMatthew G. Knepley       const PetscInt p = perm ? perm[point] : point;
29431c6742e7SMatthew G. Knepley 
2944863027abSJed Brown       switch (dm->blocking_type) {
29450e762ea3SJed Brown       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
29469fca9976SJed Brown         PetscInt bdof, offset;
2947a9d99c84SMatthew G. Knepley 
29489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
29499fca9976SJed Brown         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
29509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
29511c6742e7SMatthew G. Knepley         if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN;
295232b27637SMatthew G. Knepley         if (dof > 0) {
29531c6742e7SMatthew G. Knepley           // State change
29541c6742e7SMatthew G. Knepley           if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE;
29551c6742e7SMatthew G. Knepley           else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE;
29561c6742e7SMatthew G. Knepley 
2957d02c7345SMatthew G. Knepley           for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof;
2958d02c7345SMatthew G. Knepley           // Signal block concatenation
29591c6742e7SMatthew G. Knepley           if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof);
296032b27637SMatthew G. Knepley         }
29611d17a0a3SMatthew G. Knepley         dof  = dof < 0 ? -(dof + 1) : dof;
29621d17a0a3SMatthew G. Knepley         bdof = cdof && (dof - cdof) ? 1 : dof;
29631d17a0a3SMatthew G. Knepley         if (dof) {
29649371c9d4SSatish Balay           if (bs < 0) {
29659371c9d4SSatish Balay             bs = bdof;
29669371c9d4SSatish Balay           } else if (bs != bdof) {
29679371c9d4SSatish Balay             bs = 1;
29689371c9d4SSatish Balay           }
2969552f7358SJed Brown         }
2970863027abSJed Brown       } break;
2971863027abSJed Brown       case DM_BLOCKING_FIELD_NODE: {
2972863027abSJed Brown         for (PetscInt field = 0; field < num_fields; field++) {
2973863027abSJed Brown           PetscInt num_comp, bdof, offset;
2974863027abSJed Brown           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2975863027abSJed Brown           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2976863027abSJed Brown           if (dof < 0) continue;
2977863027abSJed Brown           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2978863027abSJed Brown           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2979863027abSJed Brown           PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp);
2980863027abSJed Brown           PetscInt num_nodes = dof / num_comp;
2981863027abSJed Brown           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2982863027abSJed Brown           // Handle possibly constant block size (unlikely)
2983863027abSJed Brown           bdof = cdof && (dof - cdof) ? 1 : dof;
2984863027abSJed Brown           if (dof) {
2985863027abSJed Brown             if (bs < 0) {
2986863027abSJed Brown               bs = bdof;
2987863027abSJed Brown             } else if (bs != bdof) {
2988863027abSJed Brown               bs = 1;
2989863027abSJed Brown             }
2990863027abSJed Brown           }
2991863027abSJed Brown         }
2992863027abSJed Brown       } break;
2993863027abSJed Brown       }
29942a28c762SMatthew G Knepley     }
29951c6742e7SMatthew G. Knepley     if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm));
29962a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
29971690c2aeSBarry Smith     bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
2998e432b41dSStefano Zampini     bsLocal[1] = bs;
29999566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
3000e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
3001e432b41dSStefano Zampini     else bs = bsMinMax[0];
30026fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
30039566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
30040682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
30059566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
30069566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
30070682b8bbSJed Brown     } else {
30089566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
30099566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
30109566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
3011552f7358SJed Brown     }
301232b27637SMatthew G. Knepley     if (pblocks) { // Consolidate blocks
30139fca9976SJed Brown       PetscInt nblocks = 0;
301432b27637SMatthew G. Knepley       pblocks[0]       = PetscAbs(pblocks[0]);
30159fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
30169fca9976SJed Brown         if (pblocks[i] == 0) continue;
3017d02c7345SMatthew G. Knepley         // Negative block size indicates the blocks should be concatenated
3018d02c7345SMatthew G. Knepley         if (pblocks[i] < 0) {
3019d02c7345SMatthew G. Knepley           pblocks[i] = -pblocks[i];
3020d02c7345SMatthew G. Knepley           pblocks[nblocks - 1] += pblocks[i];
3021d02c7345SMatthew G. Knepley         } else {
30229fca9976SJed Brown           pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
3023d02c7345SMatthew G. Knepley         }
30241c6742e7SMatthew G. Knepley         for (PetscInt j = 1; j < pblocks[i]; j++)
30251c6742e7SMatthew G. Knepley           PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j);
30269fca9976SJed Brown       }
30279fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
30289fca9976SJed Brown     }
30299fca9976SJed Brown     PetscCall(PetscFree(pblocks));
3030aa0f6e3cSJed Brown   }
30319566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
30323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3033552f7358SJed Brown }
3034552f7358SJed Brown 
30357cd05799SMatthew G. Knepley /*@
3036a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
3037be36d101SStefano Zampini 
3038a1cb98faSBarry Smith   Not Collective
3039be36d101SStefano Zampini 
3040be36d101SStefano Zampini   Input Parameter:
304160225df5SJacob Faibussowitsch . dm - The `DMPLEX`
3042be36d101SStefano Zampini 
30432fe279fdSBarry Smith   Output Parameter:
3044be36d101SStefano Zampini . subsection - The subdomain section
3045be36d101SStefano Zampini 
3046be36d101SStefano Zampini   Level: developer
3047be36d101SStefano Zampini 
30481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
30497cd05799SMatthew G. Knepley @*/
3050d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
3051d71ae5a4SJacob Faibussowitsch {
3052be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
3053be36d101SStefano Zampini 
3054be36d101SStefano Zampini   PetscFunctionBegin;
3055be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3056be36d101SStefano Zampini   if (!mesh->subdomainSection) {
3057be36d101SStefano Zampini     PetscSection section;
3058be36d101SStefano Zampini     PetscSF      sf;
3059be36d101SStefano Zampini 
30609566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
30619566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
3062eb9d3e4dSMatthew G. Knepley     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
30639566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
3064be36d101SStefano Zampini   }
3065be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
30663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3067be36d101SStefano Zampini }
3068be36d101SStefano Zampini 
3069552f7358SJed Brown /*@
307020f4b53cSBarry Smith   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
3071552f7358SJed Brown 
3072a1cb98faSBarry Smith   Not Collective
3073552f7358SJed Brown 
3074552f7358SJed Brown   Input Parameter:
307560225df5SJacob Faibussowitsch . dm - The `DMPLEX`
3076552f7358SJed Brown 
3077552f7358SJed Brown   Output Parameters:
3078552f7358SJed Brown + pStart - The first mesh point
3079552f7358SJed Brown - pEnd   - The upper bound for mesh points
3080552f7358SJed Brown 
3081552f7358SJed Brown   Level: beginner
3082552f7358SJed Brown 
30831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
3084552f7358SJed Brown @*/
3085d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
3086d71ae5a4SJacob Faibussowitsch {
3087552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3088552f7358SJed Brown 
3089552f7358SJed Brown   PetscFunctionBegin;
3090552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30919f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
30929f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
30933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3094552f7358SJed Brown }
3095552f7358SJed Brown 
3096552f7358SJed Brown /*@
309720f4b53cSBarry Smith   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
3098552f7358SJed Brown 
3099a1cb98faSBarry Smith   Not Collective
3100552f7358SJed Brown 
3101552f7358SJed Brown   Input Parameters:
310260225df5SJacob Faibussowitsch + dm     - The `DMPLEX`
3103552f7358SJed Brown . pStart - The first mesh point
3104552f7358SJed Brown - pEnd   - The upper bound for mesh points
3105552f7358SJed Brown 
3106552f7358SJed Brown   Level: beginner
3107552f7358SJed Brown 
31081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
3109552f7358SJed Brown @*/
3110d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
3111d71ae5a4SJacob Faibussowitsch {
3112552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3113552f7358SJed Brown 
3114552f7358SJed Brown   PetscFunctionBegin;
3115552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31169566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
31179566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
311821027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
31193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3120552f7358SJed Brown }
3121552f7358SJed Brown 
3122552f7358SJed Brown /*@
3123eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
3124552f7358SJed Brown 
3125a1cb98faSBarry Smith   Not Collective
3126552f7358SJed Brown 
3127552f7358SJed Brown   Input Parameters:
312860225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3129a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3130552f7358SJed Brown 
3131552f7358SJed Brown   Output Parameter:
313220f4b53cSBarry Smith . size - The cone size for point `p`
3133552f7358SJed Brown 
3134552f7358SJed Brown   Level: beginner
3135552f7358SJed Brown 
31361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3137552f7358SJed Brown @*/
3138d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
3139d71ae5a4SJacob Faibussowitsch {
3140552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3141552f7358SJed Brown 
3142552f7358SJed Brown   PetscFunctionBegin;
3143552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31444f572ea9SToby Isaac   PetscAssertPointer(size, 3);
31459f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
31469f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
31473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3148552f7358SJed Brown }
3149552f7358SJed Brown 
3150552f7358SJed Brown /*@
3151eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
3152552f7358SJed Brown 
3153a1cb98faSBarry Smith   Not Collective
3154552f7358SJed Brown 
3155552f7358SJed Brown   Input Parameters:
315660225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3157a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
315820f4b53cSBarry Smith - size - The cone size for point `p`
3159552f7358SJed Brown 
3160552f7358SJed Brown   Level: beginner
3161552f7358SJed Brown 
3162a1cb98faSBarry Smith   Note:
3163a1cb98faSBarry Smith   This should be called after `DMPlexSetChart()`.
3164a1cb98faSBarry Smith 
31652c9a7b26SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
3166552f7358SJed Brown @*/
3167d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
3168d71ae5a4SJacob Faibussowitsch {
3169552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3170552f7358SJed Brown 
3171552f7358SJed Brown   PetscFunctionBegin;
3172552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31739f4ada15SMatthew G. Knepley   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
31749566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
31753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3176552f7358SJed Brown }
3177552f7358SJed Brown 
3178552f7358SJed Brown /*@C
3179eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
3180552f7358SJed Brown 
3181a1cb98faSBarry Smith   Not Collective
3182552f7358SJed Brown 
3183552f7358SJed Brown   Input Parameters:
3184a1cb98faSBarry Smith + dm - The `DMPLEX`
3185a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3186552f7358SJed Brown 
3187552f7358SJed Brown   Output Parameter:
31882c9a7b26SBarry Smith . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()`
3189552f7358SJed Brown 
3190552f7358SJed Brown   Level: beginner
3191552f7358SJed Brown 
319260225df5SJacob Faibussowitsch   Fortran Notes:
31932c9a7b26SBarry Smith   `cone` must be declared with
31942c9a7b26SBarry Smith .vb
31952c9a7b26SBarry Smith   PetscInt, pointer :: cone(:)
31962c9a7b26SBarry Smith .ve
31972c9a7b26SBarry Smith 
3198feaf08eaSBarry Smith   You must call `DMPlexRestoreCone()` after you finish using the array.
3199a1cb98faSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
32003813dfbdSMatthew G Knepley 
32011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3202552f7358SJed Brown @*/
3203d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3204d71ae5a4SJacob Faibussowitsch {
3205552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3206552f7358SJed Brown   PetscInt off;
3207552f7358SJed Brown 
3208552f7358SJed Brown   PetscFunctionBegin;
3209552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32104f572ea9SToby Isaac   PetscAssertPointer(cone, 3);
32119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
32128e3a54c0SPierre Jolivet   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
32133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3214552f7358SJed Brown }
3215552f7358SJed Brown 
3216cc4c1da9SBarry Smith /*@
32170ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
32180ce7577fSVaclav Hapla 
3219a1cb98faSBarry Smith   Not Collective
32200ce7577fSVaclav Hapla 
32210ce7577fSVaclav Hapla   Input Parameters:
3222a1cb98faSBarry Smith + dm - The `DMPLEX`
3223a1cb98faSBarry Smith - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
32240ce7577fSVaclav Hapla 
3225d8d19677SJose E. Roman   Output Parameters:
322620f4b53cSBarry Smith + pConesSection - `PetscSection` describing the layout of `pCones`
32272c9a7b26SBarry Smith - pCones        - An `IS` containing the points which are on the in-edges for the point set `p`
32280ce7577fSVaclav Hapla 
32290ce7577fSVaclav Hapla   Level: intermediate
32300ce7577fSVaclav Hapla 
32311cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
32320ce7577fSVaclav Hapla @*/
3233ce78bad3SBarry Smith PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones)
3234d71ae5a4SJacob Faibussowitsch {
32350ce7577fSVaclav Hapla   PetscSection cs, newcs;
32360ce7577fSVaclav Hapla   PetscInt    *cones;
32370ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
32380ce7577fSVaclav Hapla   PetscInt     n;
32390ce7577fSVaclav Hapla 
32400ce7577fSVaclav Hapla   PetscFunctionBegin;
32419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
32429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
32439566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
32440ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
32450ce7577fSVaclav Hapla   if (pCones) {
32469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
32479566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
32480ce7577fSVaclav Hapla   }
32493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32500ce7577fSVaclav Hapla }
32510ce7577fSVaclav Hapla 
3252af9eab45SVaclav Hapla /*@
3253af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
3254d4636a37SVaclav Hapla 
3255a1cb98faSBarry Smith   Not Collective
3256d4636a37SVaclav Hapla 
3257d4636a37SVaclav Hapla   Input Parameters:
3258a1cb98faSBarry Smith + dm     - The `DMPLEX`
3259a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3260d4636a37SVaclav Hapla 
3261d4636a37SVaclav Hapla   Output Parameter:
32622c9a7b26SBarry Smith . expandedPoints - An `IS` containing the of vertices recursively expanded from input points
3263d4636a37SVaclav Hapla 
3264d4636a37SVaclav Hapla   Level: advanced
3265d4636a37SVaclav Hapla 
3266af9eab45SVaclav Hapla   Notes:
326720f4b53cSBarry Smith   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
3268af9eab45SVaclav Hapla 
3269a1cb98faSBarry Smith   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
3270a1cb98faSBarry Smith 
32711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3272a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`
3273d4636a37SVaclav Hapla @*/
3274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3275d71ae5a4SJacob Faibussowitsch {
3276af9eab45SVaclav Hapla   IS      *expandedPointsAll;
3277af9eab45SVaclav Hapla   PetscInt depth;
3278d4636a37SVaclav Hapla 
3279d4636a37SVaclav Hapla   PetscFunctionBegin;
3280af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3281af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
32824f572ea9SToby Isaac   PetscAssertPointer(expandedPoints, 3);
32839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3284af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
32859566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
32869566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
32873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3288af9eab45SVaclav Hapla }
3289af9eab45SVaclav Hapla 
3290af9eab45SVaclav Hapla /*@
32912c9a7b26SBarry Smith   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices
32922c9a7b26SBarry Smith   (DAG points of depth 0, i.e., without cones).
3293af9eab45SVaclav Hapla 
3294a1cb98faSBarry Smith   Not Collective
3295af9eab45SVaclav Hapla 
3296af9eab45SVaclav Hapla   Input Parameters:
3297a1cb98faSBarry Smith + dm     - The `DMPLEX`
3298a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3299af9eab45SVaclav Hapla 
3300d8d19677SJose E. Roman   Output Parameters:
3301a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3302af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
3303af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3304af9eab45SVaclav Hapla 
3305af9eab45SVaclav Hapla   Level: advanced
3306af9eab45SVaclav Hapla 
3307af9eab45SVaclav Hapla   Notes:
3308a1cb98faSBarry Smith   Like `DMPlexGetConeTuple()` but recursive.
3309af9eab45SVaclav Hapla 
3310a4e35b19SJacob Faibussowitsch   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.
3311af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
3312af9eab45SVaclav Hapla 
3313a4e35b19SJacob Faibussowitsch   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\:
3314a4e35b19SJacob Faibussowitsch   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3315a4e35b19SJacob Faibussowitsch   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
3316af9eab45SVaclav Hapla 
33171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3318a1cb98faSBarry Smith           `DMPlexGetDepth()`, `PetscSection`, `IS`
3319af9eab45SVaclav Hapla @*/
3320ce78bad3SBarry Smith PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[])
3321d71ae5a4SJacob Faibussowitsch {
3322af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
3323af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
3324af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3325af9eab45SVaclav Hapla   IS             *expandedPoints_;
3326af9eab45SVaclav Hapla   PetscSection   *sections_;
3327af9eab45SVaclav Hapla 
3328af9eab45SVaclav Hapla   PetscFunctionBegin;
3329af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3330af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
33314f572ea9SToby Isaac   if (depth) PetscAssertPointer(depth, 3);
33324f572ea9SToby Isaac   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
33334f572ea9SToby Isaac   if (sections) PetscAssertPointer(sections, 5);
33349566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
33359566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
33369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
33379566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
33389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
3339af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3340af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
33419566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
33429566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3343af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
33449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3345af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
33469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
33479566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3348af9eab45SVaclav Hapla       } else {
33499566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3350af9eab45SVaclav Hapla       }
3351af9eab45SVaclav Hapla     }
33529566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
33539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
33549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
3355af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
33569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
33579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3358af9eab45SVaclav Hapla       if (cn > 1) {
33599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3360418fb43bSPierre Jolivet         PetscCall(PetscArraycpy(&newarr[co], cone, cn));
3361af9eab45SVaclav Hapla       } else {
3362af9eab45SVaclav Hapla         newarr[co] = arr[i];
3363af9eab45SVaclav Hapla       }
3364af9eab45SVaclav Hapla     }
33659566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3366af9eab45SVaclav Hapla     arr = newarr;
3367af9eab45SVaclav Hapla     n   = newn;
3368af9eab45SVaclav Hapla   }
33699566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
3370af9eab45SVaclav Hapla   *depth = depth_;
3371af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
3372af9eab45SVaclav Hapla   else {
33739566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
33749566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
3375af9eab45SVaclav Hapla   }
3376af9eab45SVaclav Hapla   if (sections) *sections = sections_;
3377af9eab45SVaclav Hapla   else {
33789566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
33799566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
3380af9eab45SVaclav Hapla   }
33813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3382af9eab45SVaclav Hapla }
3383af9eab45SVaclav Hapla 
3384af9eab45SVaclav Hapla /*@
3385a1cb98faSBarry Smith   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3386af9eab45SVaclav Hapla 
3387a1cb98faSBarry Smith   Not Collective
3388af9eab45SVaclav Hapla 
3389af9eab45SVaclav Hapla   Input Parameters:
3390a1cb98faSBarry Smith + dm     - The `DMPLEX`
3391a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3392af9eab45SVaclav Hapla 
3393d8d19677SJose E. Roman   Output Parameters:
3394a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3395af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3396af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3397af9eab45SVaclav Hapla 
3398af9eab45SVaclav Hapla   Level: advanced
3399af9eab45SVaclav Hapla 
3400a1cb98faSBarry Smith   Note:
3401a1cb98faSBarry Smith   See `DMPlexGetConeRecursive()`
3402af9eab45SVaclav Hapla 
34031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3404a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`, `PetscSection`
3405af9eab45SVaclav Hapla @*/
3406ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[])
3407d71ae5a4SJacob Faibussowitsch {
3408af9eab45SVaclav Hapla   PetscInt d, depth_;
3409af9eab45SVaclav Hapla 
3410af9eab45SVaclav Hapla   PetscFunctionBegin;
34119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
34121dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3413af9eab45SVaclav Hapla   if (depth) *depth = 0;
3414af9eab45SVaclav Hapla   if (expandedPoints) {
341557508eceSPierre Jolivet     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d]));
34169566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3417af9eab45SVaclav Hapla   }
3418af9eab45SVaclav Hapla   if (sections) {
341957508eceSPierre Jolivet     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d]));
34209566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3421af9eab45SVaclav Hapla   }
34223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3423d4636a37SVaclav Hapla }
3424d4636a37SVaclav Hapla 
3425552f7358SJed Brown /*@
342692371b87SBarry 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
3427552f7358SJed Brown 
3428a1cb98faSBarry Smith   Not Collective
3429552f7358SJed Brown 
3430552f7358SJed Brown   Input Parameters:
343160225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3432a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
34332c9a7b26SBarry Smith - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()`
3434552f7358SJed Brown 
3435552f7358SJed Brown   Level: beginner
3436552f7358SJed Brown 
3437a1cb98faSBarry Smith   Note:
3438a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3439a1cb98faSBarry Smith 
34401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3441552f7358SJed Brown @*/
3442d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3443d71ae5a4SJacob Faibussowitsch {
3444552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3445552f7358SJed Brown   PetscInt dof, off, c;
3446552f7358SJed Brown 
3447552f7358SJed Brown   PetscFunctionBegin;
3448552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
34504f572ea9SToby Isaac   if (dof) PetscAssertPointer(cone, 3);
34519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3452db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3453db485b19SStefano Zampini     PetscInt pStart, pEnd;
3454db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
345563a3b9bcSJacob 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);
3456552f7358SJed Brown     for (c = 0; c < dof; ++c) {
345763a3b9bcSJacob 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);
3458552f7358SJed Brown       mesh->cones[off + c] = cone[c];
3459552f7358SJed Brown     }
3460db485b19SStefano Zampini   } else {
3461db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3462db485b19SStefano Zampini   }
34633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3464552f7358SJed Brown }
3465552f7358SJed Brown 
3466552f7358SJed Brown /*@C
3467eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3468552f7358SJed Brown 
3469a1cb98faSBarry Smith   Not Collective
3470552f7358SJed Brown 
3471552f7358SJed Brown   Input Parameters:
347260225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3473a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3474552f7358SJed Brown 
3475552f7358SJed Brown   Output Parameter:
347620f4b53cSBarry Smith . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
34772c9a7b26SBarry Smith                     integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()`
3478552f7358SJed Brown 
3479552f7358SJed Brown   Level: beginner
3480552f7358SJed Brown 
3481a1cb98faSBarry Smith   Note:
3482b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3483b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3484a1cb98faSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3485b5a892a1SMatthew G. Knepley   with the identity.
3486b5a892a1SMatthew G. Knepley 
348760225df5SJacob Faibussowitsch   Fortran Notes:
34882c9a7b26SBarry Smith   You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3489a1cb98faSBarry Smith   `DMPlexRestoreConeOrientation()` is not needed/available in C.
34903813dfbdSMatthew G Knepley 
34912c9a7b26SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`,
34922c9a7b26SBarry Smith           `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3493552f7358SJed Brown @*/
3494d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3495d71ae5a4SJacob Faibussowitsch {
3496552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3497552f7358SJed Brown   PetscInt off;
3498552f7358SJed Brown 
3499552f7358SJed Brown   PetscFunctionBegin;
3500552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
350176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3502552f7358SJed Brown     PetscInt dof;
35039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
35044f572ea9SToby Isaac     if (dof) PetscAssertPointer(coneOrientation, 3);
3505552f7358SJed Brown   }
35069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
35070d644c17SKarl Rupp 
3508552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
35093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3510552f7358SJed Brown }
3511552f7358SJed Brown 
3512552f7358SJed Brown /*@
3513eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3514552f7358SJed Brown 
3515a1cb98faSBarry Smith   Not Collective
3516552f7358SJed Brown 
3517552f7358SJed Brown   Input Parameters:
351860225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3519a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
35202c9a7b26SBarry Smith - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()`
3521b5a892a1SMatthew G. Knepley 
3522552f7358SJed Brown   Level: beginner
3523552f7358SJed Brown 
3524a1cb98faSBarry Smith   Notes:
3525a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3526a1cb98faSBarry Smith 
3527a1cb98faSBarry Smith   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3528a1cb98faSBarry Smith 
35291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3530552f7358SJed Brown @*/
3531d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3532d71ae5a4SJacob Faibussowitsch {
3533552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3534552f7358SJed Brown   PetscInt pStart, pEnd;
3535552f7358SJed Brown   PetscInt dof, off, c;
3536552f7358SJed Brown 
3537552f7358SJed Brown   PetscFunctionBegin;
3538552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
35404f572ea9SToby Isaac   if (dof) PetscAssertPointer(coneOrientation, 3);
35419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3542db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3543db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
354463a3b9bcSJacob 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);
3545552f7358SJed Brown     for (c = 0; c < dof; ++c) {
3546552f7358SJed Brown       PetscInt cdof, o = coneOrientation[c];
3547552f7358SJed Brown 
35489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
35491dca8a05SBarry 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);
3550552f7358SJed Brown       mesh->coneOrientations[off + c] = o;
3551552f7358SJed Brown     }
3552db485b19SStefano Zampini   } else {
3553db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3554db485b19SStefano Zampini   }
35553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3556552f7358SJed Brown }
3557552f7358SJed Brown 
35587cd05799SMatthew G. Knepley /*@
3559eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
35607cd05799SMatthew G. Knepley 
3561a1cb98faSBarry Smith   Not Collective
35627cd05799SMatthew G. Knepley 
35637cd05799SMatthew G. Knepley   Input Parameters:
356460225df5SJacob Faibussowitsch + dm        - The `DMPLEX`
3565a1cb98faSBarry Smith . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
35667cd05799SMatthew G. Knepley . conePos   - The local index in the cone where the point should be put
35677cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
35687cd05799SMatthew G. Knepley 
35697cd05799SMatthew G. Knepley   Level: beginner
35707cd05799SMatthew G. Knepley 
35711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
35727cd05799SMatthew G. Knepley @*/
3573d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3574d71ae5a4SJacob Faibussowitsch {
3575552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3576552f7358SJed Brown   PetscInt pStart, pEnd;
3577552f7358SJed Brown   PetscInt dof, off;
3578552f7358SJed Brown 
3579552f7358SJed Brown   PetscFunctionBegin;
3580552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3581a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
35829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
358363a3b9bcSJacob 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);
358463a3b9bcSJacob 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);
35859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
358663a3b9bcSJacob 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);
3587a03d55ffSStefano Zampini   }
3588a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3589552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
35903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3591552f7358SJed Brown }
3592552f7358SJed Brown 
35937cd05799SMatthew G. Knepley /*@
3594eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
35957cd05799SMatthew G. Knepley 
3596a1cb98faSBarry Smith   Not Collective
35977cd05799SMatthew G. Knepley 
35987cd05799SMatthew G. Knepley   Input Parameters:
359960225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3600a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
36017cd05799SMatthew G. Knepley . conePos         - The local index in the cone where the point should be put
36027cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
36037cd05799SMatthew G. Knepley 
36047cd05799SMatthew G. Knepley   Level: beginner
36057cd05799SMatthew G. Knepley 
3606a1cb98faSBarry Smith   Note:
3607a1cb98faSBarry Smith   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3608b5a892a1SMatthew G. Knepley 
36091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
36107cd05799SMatthew G. Knepley @*/
3611d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3612d71ae5a4SJacob Faibussowitsch {
361377c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
361477c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
361577c88f5bSMatthew G Knepley   PetscInt dof, off;
361677c88f5bSMatthew G Knepley 
361777c88f5bSMatthew G Knepley   PetscFunctionBegin;
361877c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3619a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
36209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
362163a3b9bcSJacob 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);
36229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
362363a3b9bcSJacob 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);
3624a03d55ffSStefano Zampini   }
3625a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
362677c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
36273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
362877c88f5bSMatthew G Knepley }
362977c88f5bSMatthew G Knepley 
36309f4ada15SMatthew G. Knepley /*@C
36319f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
36329f4ada15SMatthew G. Knepley 
36339f4ada15SMatthew G. Knepley   Not collective
36349f4ada15SMatthew G. Knepley 
36359f4ada15SMatthew G. Knepley   Input Parameters:
36369f4ada15SMatthew G. Knepley + dm - The DMPlex
36379f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
36389f4ada15SMatthew G. Knepley 
36399f4ada15SMatthew G. Knepley   Output Parameters:
364020f4b53cSBarry Smith + cone - An array of points which are on the in-edges for point `p`
364120f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
36429f4ada15SMatthew G. Knepley          integer giving the prescription for cone traversal.
36439f4ada15SMatthew G. Knepley 
36449f4ada15SMatthew G. Knepley   Level: beginner
36459f4ada15SMatthew G. Knepley 
36469f4ada15SMatthew G. Knepley   Notes:
36479f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
36489f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
364920f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
36509f4ada15SMatthew G. Knepley   with the identity.
36519f4ada15SMatthew G. Knepley 
36522c9a7b26SBarry Smith   You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array.
36532c9a7b26SBarry Smith 
36549f4ada15SMatthew G. Knepley   Fortran Notes:
36552c9a7b26SBarry Smith   `cone` and `ornt` must be declared with
36562c9a7b26SBarry Smith .vb
36572c9a7b26SBarry Smith   PetscInt, pointer :: cone(:)
36582c9a7b26SBarry Smith   PetscInt, pointer :: ornt(:)
36592c9a7b26SBarry Smith .ve
36609f4ada15SMatthew G. Knepley 
36611cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
36629f4ada15SMatthew G. Knepley @*/
3663ce78bad3SBarry Smith PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[])
36649f4ada15SMatthew G. Knepley {
36659f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
36669f4ada15SMatthew G. Knepley 
36679f4ada15SMatthew G. Knepley   PetscFunctionBegin;
36689f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36699f4ada15SMatthew G. Knepley   if (mesh->tr) {
36709f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
36719f4ada15SMatthew G. Knepley   } else {
36729f4ada15SMatthew G. Knepley     PetscInt off;
36739f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
36749f4ada15SMatthew G. Knepley       PetscInt dof;
36759f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
36769f4ada15SMatthew G. Knepley       if (dof) {
36774f572ea9SToby Isaac         if (cone) PetscAssertPointer(cone, 3);
36784f572ea9SToby Isaac         if (ornt) PetscAssertPointer(ornt, 4);
36799f4ada15SMatthew G. Knepley       }
36809f4ada15SMatthew G. Knepley     }
36819f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
36828e3a54c0SPierre Jolivet     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
36838e3a54c0SPierre Jolivet     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
36849f4ada15SMatthew G. Knepley   }
36853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36869f4ada15SMatthew G. Knepley }
36879f4ada15SMatthew G. Knepley 
36889f4ada15SMatthew G. Knepley /*@C
36892c9a7b26SBarry Smith   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()`
36909f4ada15SMatthew G. Knepley 
369120f4b53cSBarry Smith   Not Collective
36929f4ada15SMatthew G. Knepley 
36939f4ada15SMatthew G. Knepley   Input Parameters:
36949f4ada15SMatthew G. Knepley + dm   - The DMPlex
369520f4b53cSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
36969f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
369720f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
36989f4ada15SMatthew G. Knepley          integer giving the prescription for cone traversal.
36999f4ada15SMatthew G. Knepley 
37009f4ada15SMatthew G. Knepley   Level: beginner
37019f4ada15SMatthew G. Knepley 
37021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
37039f4ada15SMatthew G. Knepley @*/
37049f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
37059f4ada15SMatthew G. Knepley {
37069f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
37079f4ada15SMatthew G. Knepley 
37089f4ada15SMatthew G. Knepley   PetscFunctionBegin;
37099f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37109f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
37113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37129f4ada15SMatthew G. Knepley }
37139f4ada15SMatthew G. Knepley 
3714552f7358SJed Brown /*@
3715eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3716552f7358SJed Brown 
3717a1cb98faSBarry Smith   Not Collective
3718552f7358SJed Brown 
3719552f7358SJed Brown   Input Parameters:
372060225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3721a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3722552f7358SJed Brown 
3723552f7358SJed Brown   Output Parameter:
372420f4b53cSBarry Smith . size - The support size for point `p`
3725552f7358SJed Brown 
3726552f7358SJed Brown   Level: beginner
3727552f7358SJed Brown 
37281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3729552f7358SJed Brown @*/
3730d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3731d71ae5a4SJacob Faibussowitsch {
3732552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3733552f7358SJed Brown 
3734552f7358SJed Brown   PetscFunctionBegin;
3735552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37364f572ea9SToby Isaac   PetscAssertPointer(size, 3);
37379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
37383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3739552f7358SJed Brown }
3740552f7358SJed Brown 
3741552f7358SJed Brown /*@
3742eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3743552f7358SJed Brown 
3744a1cb98faSBarry Smith   Not Collective
3745552f7358SJed Brown 
3746552f7358SJed Brown   Input Parameters:
374760225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3748a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
374920f4b53cSBarry Smith - size - The support size for point `p`
3750552f7358SJed Brown 
3751a1cb98faSBarry Smith   Level: beginner
3752552f7358SJed Brown 
3753552f7358SJed Brown   Note:
375420f4b53cSBarry Smith   This should be called after `DMPlexSetChart()`.
3755552f7358SJed Brown 
37561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3757552f7358SJed Brown @*/
3758d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3759d71ae5a4SJacob Faibussowitsch {
3760552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3761552f7358SJed Brown 
3762552f7358SJed Brown   PetscFunctionBegin;
3763552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
37653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3766552f7358SJed Brown }
3767552f7358SJed Brown 
3768552f7358SJed Brown /*@C
3769eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3770552f7358SJed Brown 
3771a1cb98faSBarry Smith   Not Collective
3772552f7358SJed Brown 
3773552f7358SJed Brown   Input Parameters:
377460225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3775a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3776552f7358SJed Brown 
3777552f7358SJed Brown   Output Parameter:
37782c9a7b26SBarry Smith . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3779552f7358SJed Brown 
3780552f7358SJed Brown   Level: beginner
3781552f7358SJed Brown 
378260225df5SJacob Faibussowitsch   Fortran Notes:
37832c9a7b26SBarry Smith   `support` must be declared with
37842c9a7b26SBarry Smith .vb
37852c9a7b26SBarry Smith   PetscInt, pointer :: support(:)
37862c9a7b26SBarry Smith .ve
37872c9a7b26SBarry Smith 
3788a1cb98faSBarry Smith   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3789a1cb98faSBarry Smith   `DMPlexRestoreSupport()` is not needed/available in C.
37903813dfbdSMatthew G Knepley 
37911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3792552f7358SJed Brown @*/
3793d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3794d71ae5a4SJacob Faibussowitsch {
3795552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3796552f7358SJed Brown   PetscInt off;
3797552f7358SJed Brown 
3798552f7358SJed Brown   PetscFunctionBegin;
3799552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38004f572ea9SToby Isaac   PetscAssertPointer(support, 3);
38019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
38028e3a54c0SPierre Jolivet   *support = PetscSafePointerPlusOffset(mesh->supports, off);
38033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3804552f7358SJed Brown }
3805552f7358SJed Brown 
3806552f7358SJed Brown /*@
380792371b87SBarry 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
3808552f7358SJed Brown 
3809a1cb98faSBarry Smith   Not Collective
3810552f7358SJed Brown 
3811552f7358SJed Brown   Input Parameters:
381260225df5SJacob Faibussowitsch + dm      - The `DMPLEX`
3813a1cb98faSBarry Smith . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
38142c9a7b26SBarry Smith - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3815552f7358SJed Brown 
3816552f7358SJed Brown   Level: beginner
3817552f7358SJed Brown 
3818a1cb98faSBarry Smith   Note:
3819a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3820a1cb98faSBarry Smith 
38211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3822552f7358SJed Brown @*/
3823d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3824d71ae5a4SJacob Faibussowitsch {
3825552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3826552f7358SJed Brown   PetscInt pStart, pEnd;
3827552f7358SJed Brown   PetscInt dof, off, c;
3828552f7358SJed Brown 
3829552f7358SJed Brown   PetscFunctionBegin;
3830552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
38329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
38334f572ea9SToby Isaac   if (dof) PetscAssertPointer(support, 3);
38349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
383563a3b9bcSJacob 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);
3836552f7358SJed Brown   for (c = 0; c < dof; ++c) {
383763a3b9bcSJacob 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);
3838552f7358SJed Brown     mesh->supports[off + c] = support[c];
3839552f7358SJed Brown   }
38403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3841552f7358SJed Brown }
3842552f7358SJed Brown 
38437cd05799SMatthew G. Knepley /*@
3844eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
38457cd05799SMatthew G. Knepley 
3846a1cb98faSBarry Smith   Not Collective
38477cd05799SMatthew G. Knepley 
38487cd05799SMatthew G. Knepley   Input Parameters:
384960225df5SJacob Faibussowitsch + dm           - The `DMPLEX`
3850a1cb98faSBarry Smith . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
38517cd05799SMatthew G. Knepley . supportPos   - The local index in the cone where the point should be put
38527cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
38537cd05799SMatthew G. Knepley 
38547cd05799SMatthew G. Knepley   Level: beginner
38557cd05799SMatthew G. Knepley 
38561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
38577cd05799SMatthew G. Knepley @*/
3858d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3859d71ae5a4SJacob Faibussowitsch {
3860552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3861552f7358SJed Brown   PetscInt pStart, pEnd;
3862552f7358SJed Brown   PetscInt dof, off;
3863552f7358SJed Brown 
3864552f7358SJed Brown   PetscFunctionBegin;
3865552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
38679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
38689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
386963a3b9bcSJacob 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);
387063a3b9bcSJacob 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);
387163a3b9bcSJacob 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);
3872552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
38733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3874552f7358SJed Brown }
3875552f7358SJed Brown 
3876b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3877d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3878d71ae5a4SJacob Faibussowitsch {
3879b5a892a1SMatthew G. Knepley   switch (ct) {
3880b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3881b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3882b5a892a1SMatthew G. Knepley     break;
3883b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3884b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3885b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3886b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3887b5a892a1SMatthew G. Knepley     break;
3888b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3889b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3890b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3891b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3892b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3893b5a892a1SMatthew G. Knepley     break;
3894d71ae5a4SJacob Faibussowitsch   default:
3895d71ae5a4SJacob Faibussowitsch     return o;
3896b5a892a1SMatthew G. Knepley   }
3897b5a892a1SMatthew G. Knepley   return o;
3898b5a892a1SMatthew G. Knepley }
3899b5a892a1SMatthew G. Knepley 
3900b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3901d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3902d71ae5a4SJacob Faibussowitsch {
3903b5a892a1SMatthew G. Knepley   switch (ct) {
3904b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3905b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3906b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3907b5a892a1SMatthew G. Knepley     break;
3908b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3909b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3910b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3911b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3912b5a892a1SMatthew G. Knepley     break;
3913b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3914b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3915b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3916b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3917b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3918b5a892a1SMatthew G. Knepley     break;
3919d71ae5a4SJacob Faibussowitsch   default:
3920d71ae5a4SJacob Faibussowitsch     return o;
3921b5a892a1SMatthew G. Knepley   }
3922b5a892a1SMatthew G. Knepley   return o;
3923b5a892a1SMatthew G. Knepley }
3924b5a892a1SMatthew G. Knepley 
3925b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3926d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3927d71ae5a4SJacob Faibussowitsch {
3928b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3929b5a892a1SMatthew G. Knepley 
3930b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
39319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3932b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3933b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3934b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3935b5a892a1SMatthew G. Knepley 
39369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
39379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
39389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3939b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3940b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3941b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3942b5a892a1SMatthew G. Knepley 
39439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3944b5a892a1SMatthew G. Knepley       switch (ct) {
3945b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
39469566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
39479566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3948b5a892a1SMatthew G. Knepley         break;
3949b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
39509566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
39519566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
39529566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3953b5a892a1SMatthew G. Knepley         break;
3954b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
39559566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
39569566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
39579566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
39589566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3959b5a892a1SMatthew G. Knepley         break;
3960d71ae5a4SJacob Faibussowitsch       default:
3961d71ae5a4SJacob Faibussowitsch         break;
3962b5a892a1SMatthew G. Knepley       }
3963b5a892a1SMatthew G. Knepley     }
3964b5a892a1SMatthew G. Knepley   }
39653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3966b5a892a1SMatthew G. Knepley }
3967b5a892a1SMatthew G. Knepley 
396809015e70SStefano Zampini static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
396909015e70SStefano Zampini {
397009015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
397109015e70SStefano Zampini 
397209015e70SStefano Zampini   PetscFunctionBeginHot;
397309015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
397409015e70SStefano Zampini     if (useCone) {
397509015e70SStefano Zampini       PetscCall(DMPlexGetConeSize(dm, p, size));
397609015e70SStefano Zampini       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
397709015e70SStefano Zampini     } else {
397809015e70SStefano Zampini       PetscCall(DMPlexGetSupportSize(dm, p, size));
397909015e70SStefano Zampini       PetscCall(DMPlexGetSupport(dm, p, arr));
398009015e70SStefano Zampini     }
398109015e70SStefano Zampini   } else {
398209015e70SStefano Zampini     if (useCone) {
398309015e70SStefano Zampini       const PetscSection s   = mesh->coneSection;
398409015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
398509015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
398609015e70SStefano Zampini 
398709015e70SStefano Zampini       *size = s->atlasDof[ps];
398809015e70SStefano Zampini       *arr  = mesh->cones + off;
398909015e70SStefano Zampini       *ornt = mesh->coneOrientations + off;
399009015e70SStefano Zampini     } else {
399109015e70SStefano Zampini       const PetscSection s   = mesh->supportSection;
399209015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
399309015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
399409015e70SStefano Zampini 
399509015e70SStefano Zampini       *size = s->atlasDof[ps];
399609015e70SStefano Zampini       *arr  = mesh->supports + off;
399709015e70SStefano Zampini     }
399809015e70SStefano Zampini   }
399909015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
400009015e70SStefano Zampini }
400109015e70SStefano Zampini 
400209015e70SStefano Zampini static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
400309015e70SStefano Zampini {
400409015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
400509015e70SStefano Zampini 
400609015e70SStefano Zampini   PetscFunctionBeginHot;
400709015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
400809015e70SStefano Zampini     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
400909015e70SStefano Zampini   }
401009015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
401109015e70SStefano Zampini }
401209015e70SStefano Zampini 
4013d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4014d71ae5a4SJacob Faibussowitsch {
4015b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
4016b5a892a1SMatthew G. Knepley   PetscInt       *closure;
4017b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
4018b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
4019b5a892a1SMatthew G. Knepley 
4020b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4021b5a892a1SMatthew G. Knepley   if (ornt) {
40229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
4023476787b7SMatthew G. Knepley     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN;
4024b5a892a1SMatthew G. Knepley   }
4025b5a892a1SMatthew G. Knepley   if (*points) {
4026b5a892a1SMatthew G. Knepley     closure = *points;
4027b5a892a1SMatthew G. Knepley   } else {
4028b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
40299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
40309566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
4031b5a892a1SMatthew G. Knepley   }
403209015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
4033b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
4034b5a892a1SMatthew G. Knepley     closure[off++] = p;
4035b5a892a1SMatthew G. Knepley     closure[off++] = 0;
4036b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4037b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
4038b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
4039b5a892a1SMatthew G. Knepley     }
4040b5a892a1SMatthew G. Knepley   } else {
404185036b15SMatthew G. Knepley     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);
4042b5a892a1SMatthew G. Knepley 
4043b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
4044b5a892a1SMatthew G. Knepley     closure[off++] = p;
4045b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
4046b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4047b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
4048b5a892a1SMatthew G. Knepley 
40499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
4050b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
4051b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
4052b5a892a1SMatthew G. Knepley     }
4053b5a892a1SMatthew G. Knepley   }
405409015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
4055b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
4056b5a892a1SMatthew G. Knepley   if (points) *points = closure;
40573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4058b5a892a1SMatthew G. Knepley }
4059b5a892a1SMatthew G. Knepley 
4060d5b43468SJose E. Roman /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
4061d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
4062d71ae5a4SJacob Faibussowitsch {
406385036b15SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
4064b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
4065b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
4066b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
4067b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
4068b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
4069b5a892a1SMatthew G. Knepley 
4070b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
40719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
407209015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
40739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4074b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
4075b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
4076b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
40779371c9d4SSatish Balay   if (*points) {
40789371c9d4SSatish Balay     pts = *points;
40799371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
4080b5a892a1SMatthew G. Knepley   c        = 0;
4081b5a892a1SMatthew G. Knepley   pts[c++] = point;
4082b5a892a1SMatthew G. Knepley   pts[c++] = o;
40839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
40849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
40859371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
40869371c9d4SSatish Balay     pts[c++] = closure[cl];
40879371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
40889371c9d4SSatish Balay   }
40899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
40909371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
40919371c9d4SSatish Balay     pts[c++] = closure[cl];
40929371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
40939371c9d4SSatish Balay   }
40949566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
4095b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
40969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
4097b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
4098b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
4099b5a892a1SMatthew G. Knepley   }
410009015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
4101b5a892a1SMatthew G. Knepley   if (dim >= 3) {
4102b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
4103b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
4104b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
4105b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
4106b5a892a1SMatthew G. Knepley 
41079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
410885036b15SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
410909015e70SStefano Zampini       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4110b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
4111b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
4112b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
4113b5a892a1SMatthew G. Knepley 
41149371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
41159371c9d4SSatish Balay           if (pts[i] == cp) break;
4116b5a892a1SMatthew G. Knepley         if (i == c) {
41179566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
4118b5a892a1SMatthew G. Knepley           pts[c++] = cp;
4119b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
4120b5a892a1SMatthew G. Knepley         }
4121b5a892a1SMatthew G. Knepley       }
412209015e70SStefano Zampini       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4123b5a892a1SMatthew G. Knepley     }
4124b5a892a1SMatthew G. Knepley   }
4125b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
4126b5a892a1SMatthew G. Knepley   *points    = pts;
41273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4128b5a892a1SMatthew G. Knepley }
4129b5a892a1SMatthew G. Knepley 
4130d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4131d71ae5a4SJacob Faibussowitsch {
4132b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
4133b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
4134b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
4135b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
4136b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
4137b5a892a1SMatthew G. Knepley 
4138b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
41399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
4140b5a892a1SMatthew G. Knepley   if (depth == 1) {
41419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
41423ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4143b5a892a1SMatthew G. Knepley   }
41449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
4145476787b7SMatthew G. Knepley   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN;
4146c306944fSJed Brown   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
41479566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
41483ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4149b5a892a1SMatthew G. Knepley   }
41509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4151b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
4152b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
4153b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
41549566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
41559371c9d4SSatish Balay   if (*points) {
41569371c9d4SSatish Balay     closure = *points;
41579371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
4158b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
4159b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
4160b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
4161b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
4162b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
4163b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
4164b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
4165b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
4166b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
4167b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
416885036b15SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
416909015e70SStefano Zampini     const PetscInt      *tmp, *tmpO = NULL;
4170b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
4171b5a892a1SMatthew G. Knepley 
4172b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
417385036b15SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
417463a3b9bcSJacob 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);
4175b5a892a1SMatthew G. Knepley     }
417609015e70SStefano Zampini     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4177b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4178b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4179b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4180b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
41819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4182b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4183b5a892a1SMatthew G. Knepley       PetscInt       c;
4184b5a892a1SMatthew G. Knepley 
4185b5a892a1SMatthew G. Knepley       /* Check for duplicate */
4186b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
4187b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
4188b5a892a1SMatthew G. Knepley       }
4189b5a892a1SMatthew G. Knepley       if (c == closureSize) {
4190b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
4191b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
4192b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
4193b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
4194b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
4195b5a892a1SMatthew G. Knepley       }
4196b5a892a1SMatthew G. Knepley     }
419709015e70SStefano Zampini     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4198b5a892a1SMatthew G. Knepley   }
41999566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4200b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
4201b5a892a1SMatthew G. Knepley   if (points) *points = closure;
42023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4203b5a892a1SMatthew G. Knepley }
4204b5a892a1SMatthew G. Knepley 
4205552f7358SJed Brown /*@C
4206eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
4207552f7358SJed Brown 
4208a1cb98faSBarry Smith   Not Collective
4209552f7358SJed Brown 
4210552f7358SJed Brown   Input Parameters:
4211a1cb98faSBarry Smith + dm      - The `DMPLEX`
4212b5a892a1SMatthew G. Knepley . p       - The mesh point
4213*7d8e5ce9SJames Wright - useCone - `PETSC_TRUE` for the closure, otherwise return the support
4214552f7358SJed Brown 
42156b867d5aSJose E. Roman   Input/Output Parameter:
42166b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
42172c9a7b26SBarry Smith            if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`,
42182c9a7b26SBarry Smith            otherwise the provided array is used to hold the values
42196b867d5aSJose E. Roman 
42206b867d5aSJose E. Roman   Output Parameter:
42212c9a7b26SBarry Smith . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints`
4222552f7358SJed Brown 
4223a1cb98faSBarry Smith   Level: beginner
4224a1cb98faSBarry Smith 
4225552f7358SJed Brown   Note:
422620f4b53cSBarry Smith   If using internal storage (points is `NULL` on input), each call overwrites the last output.
4227552f7358SJed Brown 
422860225df5SJacob Faibussowitsch   Fortran Notes:
42292c9a7b26SBarry Smith   `points` must be declared with
42302c9a7b26SBarry Smith .vb
42312c9a7b26SBarry Smith   PetscInt, pointer :: points(:)
42322c9a7b26SBarry Smith .ve
42332c9a7b26SBarry Smith   and is always allocated by the function.
42342c9a7b26SBarry Smith 
4235feaf08eaSBarry Smith   Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed
42363813dfbdSMatthew G Knepley 
42371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4238552f7358SJed Brown @*/
4239d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4240d71ae5a4SJacob Faibussowitsch {
4241b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4242552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42434f572ea9SToby Isaac   if (numPoints) PetscAssertPointer(numPoints, 4);
42444f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 5);
4245332e0eaaSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) {
4246332e0eaaSMatthew G. Knepley     PetscInt pStart, pEnd;
4247332e0eaaSMatthew G. Knepley     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4248332e0eaaSMatthew G. Knepley     PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
4249332e0eaaSMatthew G. Knepley   }
42509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
42513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42529bf0dad6SMatthew G. Knepley }
42539bf0dad6SMatthew G. Knepley 
4254552f7358SJed Brown /*@C
4255eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
4256552f7358SJed Brown 
4257a1cb98faSBarry Smith   Not Collective
4258552f7358SJed Brown 
4259552f7358SJed Brown   Input Parameters:
4260a1cb98faSBarry Smith + dm        - The `DMPLEX`
4261b5a892a1SMatthew G. Knepley . p         - The mesh point
4262a1cb98faSBarry Smith . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
426320f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4264b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
4265552f7358SJed Brown 
4266a1cb98faSBarry Smith   Level: beginner
4267a1cb98faSBarry Smith 
4268552f7358SJed Brown   Note:
426920f4b53cSBarry Smith   If not using internal storage (points is not `NULL` on input), this call is unnecessary
4270552f7358SJed Brown 
42711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4272552f7358SJed Brown @*/
4273d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4274d71ae5a4SJacob Faibussowitsch {
4275b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4276552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42774ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
42789566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
42793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4280552f7358SJed Brown }
4281552f7358SJed Brown 
4282552f7358SJed Brown /*@
4283eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
4284552f7358SJed Brown 
4285a1cb98faSBarry Smith   Not Collective
4286552f7358SJed Brown 
4287552f7358SJed Brown   Input Parameter:
428860225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4289552f7358SJed Brown 
4290552f7358SJed Brown   Output Parameters:
4291552f7358SJed Brown + maxConeSize    - The maximum number of in-edges
4292552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
4293552f7358SJed Brown 
4294552f7358SJed Brown   Level: beginner
4295552f7358SJed Brown 
42961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4297552f7358SJed Brown @*/
4298ce78bad3SBarry Smith PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize)
4299d71ae5a4SJacob Faibussowitsch {
4300552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
4301552f7358SJed Brown 
4302552f7358SJed Brown   PetscFunctionBegin;
4303552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43041baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
43051baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
43063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4307552f7358SJed Brown }
4308552f7358SJed Brown 
4309d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
4310d71ae5a4SJacob Faibussowitsch {
4311552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
43126302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
4313552f7358SJed Brown 
4314552f7358SJed Brown   PetscFunctionBegin;
4315552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43169566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
43179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
43189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
43199566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
43206302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
43216302a7fbSVaclav Hapla   if (maxSupportSize) {
43229566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
43239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
43249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
4325552f7358SJed Brown   }
43263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4327552f7358SJed Brown }
4328552f7358SJed Brown 
4329d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4330d71ae5a4SJacob Faibussowitsch {
4331552f7358SJed Brown   PetscFunctionBegin;
43329566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
4333dd072f5fSMatthew G. Knepley   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
4334ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
4335736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
433695602cf2SAlexis Marboeuf     PetscSF sfNatural;
4337f94b4a02SBlaise Bourdin 
43383dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
43399566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
434095602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4341c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
4342f94b4a02SBlaise Bourdin   }
43433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4344552f7358SJed Brown }
4345552f7358SJed Brown 
4346d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4347d71ae5a4SJacob Faibussowitsch {
43483dcd263cSBlaise Bourdin   PetscInt i = 0;
43492adcc780SMatthew G. Knepley 
43502adcc780SMatthew G. Knepley   PetscFunctionBegin;
43519566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
43529566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4353c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
43543dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
43553dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
435695602cf2SAlexis Marboeuf       PetscSF sfNatural;
43573dcd263cSBlaise Bourdin 
43583dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
43599566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4360c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
436195602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4362c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
43633dcd263cSBlaise Bourdin       break;
43643dcd263cSBlaise Bourdin     }
43653dcd263cSBlaise Bourdin   }
43663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43672adcc780SMatthew G. Knepley }
43682adcc780SMatthew G. Knepley 
4369552f7358SJed Brown /*@
4370eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4371552f7358SJed Brown 
4372a1cb98faSBarry Smith   Not Collective
4373552f7358SJed Brown 
4374552f7358SJed Brown   Input Parameter:
437560225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4376552f7358SJed Brown 
4377552f7358SJed Brown   Level: beginner
4378552f7358SJed Brown 
4379a1cb98faSBarry Smith   Note:
4380a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetCone()`
4381a1cb98faSBarry Smith 
43821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4383552f7358SJed Brown @*/
4384d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
4385d71ae5a4SJacob Faibussowitsch {
4386552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4387552f7358SJed Brown   PetscInt *offsets;
4388552f7358SJed Brown   PetscInt  supportSize;
4389552f7358SJed Brown   PetscInt  pStart, pEnd, p;
4390552f7358SJed Brown 
4391552f7358SJed Brown   PetscFunctionBegin;
4392552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
439328b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
43949566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4395552f7358SJed Brown   /* Calculate support sizes */
43969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4397552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4398552f7358SJed Brown     PetscInt dof, off, c;
4399552f7358SJed Brown 
44009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
44019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
440248a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4403552f7358SJed Brown   }
44049566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
4405552f7358SJed Brown   /* Calculate supports */
44069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
44079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
44089566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4409552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4410552f7358SJed Brown     PetscInt dof, off, c;
4411552f7358SJed Brown 
44129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
44139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4414552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
4415552f7358SJed Brown       const PetscInt q = mesh->cones[c];
4416552f7358SJed Brown       PetscInt       offS;
4417552f7358SJed Brown 
44189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
44190d644c17SKarl Rupp 
4420552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
4421552f7358SJed Brown       ++offsets[q];
4422552f7358SJed Brown     }
4423552f7358SJed Brown   }
44249566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
44259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
44263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4427552f7358SJed Brown }
4428552f7358SJed Brown 
4429d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4430d71ae5a4SJacob Faibussowitsch {
4431277ea44aSLisandro Dalcin   IS stratumIS;
4432277ea44aSLisandro Dalcin 
4433277ea44aSLisandro Dalcin   PetscFunctionBegin;
44343ba16761SJacob Faibussowitsch   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
443576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4436277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4437277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
44389566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4439277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
44409566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
44419371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
44429371c9d4SSatish Balay         overlap = PETSC_TRUE;
44439371c9d4SSatish Balay         break;
44449371c9d4SSatish Balay       }
4445277ea44aSLisandro Dalcin     }
444663a3b9bcSJacob 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);
4447277ea44aSLisandro Dalcin   }
44489566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
44499566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
44509566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
44513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4452277ea44aSLisandro Dalcin }
4453277ea44aSLisandro Dalcin 
4454e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4455e91fa0a1SMatthew G. Knepley {
4456e91fa0a1SMatthew G. Knepley   PetscInt *pMin, *pMax;
4457e91fa0a1SMatthew G. Knepley   PetscInt  pStart, pEnd;
44581690c2aeSBarry Smith   PetscInt  dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN;
4459e91fa0a1SMatthew G. Knepley 
4460e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4461e91fa0a1SMatthew G. Knepley   {
4462e91fa0a1SMatthew G. Knepley     DMLabel label2;
4463e91fa0a1SMatthew G. Knepley 
4464e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4465e91fa0a1SMatthew G. Knepley     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4466e91fa0a1SMatthew G. Knepley   }
4467e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4468e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4469e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4470e91fa0a1SMatthew G. Knepley 
4471e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4472e91fa0a1SMatthew G. Knepley     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4473e91fa0a1SMatthew G. Knepley     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4474e91fa0a1SMatthew G. Knepley   }
4475e91fa0a1SMatthew G. Knepley   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4476e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
44771690c2aeSBarry Smith     pMin[d] = PETSC_INT_MAX;
44781690c2aeSBarry Smith     pMax[d] = PETSC_INT_MIN;
4479e91fa0a1SMatthew G. Knepley   }
4480e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4481e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4482e91fa0a1SMatthew G. Knepley     PetscInt       d;
4483e91fa0a1SMatthew G. Knepley 
4484e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4485e91fa0a1SMatthew G. Knepley     d       = DMPolytopeTypeGetDim(ct);
4486e91fa0a1SMatthew G. Knepley     pMin[d] = PetscMin(p, pMin[d]);
4487e91fa0a1SMatthew G. Knepley     pMax[d] = PetscMax(p, pMax[d]);
4488e91fa0a1SMatthew G. Knepley   }
4489e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4490e91fa0a1SMatthew G. Knepley     if (pMin[d] > pMax[d]) continue;
4491e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4492e91fa0a1SMatthew G. Knepley   }
4493e91fa0a1SMatthew G. Knepley   PetscCall(PetscFree2(pMin, pMax));
4494e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4495e91fa0a1SMatthew G. Knepley }
4496e91fa0a1SMatthew G. Knepley 
4497e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4498e91fa0a1SMatthew G. Knepley {
4499e91fa0a1SMatthew G. Knepley   PetscInt pStart, pEnd;
4500e91fa0a1SMatthew G. Knepley   PetscInt numRoots = 0, numLeaves = 0;
4501e91fa0a1SMatthew G. Knepley 
4502e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4503e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4504e91fa0a1SMatthew G. Knepley   {
4505e91fa0a1SMatthew G. Knepley     /* Initialize roots and count leaves */
45061690c2aeSBarry Smith     PetscInt sMin = PETSC_INT_MAX;
45071690c2aeSBarry Smith     PetscInt sMax = PETSC_INT_MIN;
4508e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4509e91fa0a1SMatthew G. Knepley 
4510e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4511e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4512e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4513e91fa0a1SMatthew G. Knepley       if (!coneSize && supportSize) {
4514e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4515e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4516e91fa0a1SMatthew G. Knepley         ++numRoots;
4517e91fa0a1SMatthew G. Knepley       } else if (!supportSize && coneSize) {
4518e91fa0a1SMatthew G. Knepley         ++numLeaves;
4519e91fa0a1SMatthew G. Knepley       } else if (!supportSize && !coneSize) {
4520e91fa0a1SMatthew G. Knepley         /* Isolated points */
4521e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4522e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4523e91fa0a1SMatthew G. Knepley       }
4524e91fa0a1SMatthew G. Knepley     }
4525e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4526e91fa0a1SMatthew G. Knepley   }
4527e91fa0a1SMatthew G. Knepley 
4528e91fa0a1SMatthew G. Knepley   if (numRoots + numLeaves == (pEnd - pStart)) {
45291690c2aeSBarry Smith     PetscInt sMin = PETSC_INT_MAX;
45301690c2aeSBarry Smith     PetscInt sMax = PETSC_INT_MIN;
4531e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4532e91fa0a1SMatthew G. Knepley 
4533e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4534e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4535e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4536e91fa0a1SMatthew G. Knepley       if (!supportSize && coneSize) {
4537e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4538e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4539e91fa0a1SMatthew G. Knepley       }
4540e91fa0a1SMatthew G. Knepley     }
4541e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4542e91fa0a1SMatthew G. Knepley   } else {
4543e91fa0a1SMatthew G. Knepley     PetscInt level = 0;
4544e91fa0a1SMatthew G. Knepley     PetscInt qStart, qEnd;
4545e91fa0a1SMatthew G. Knepley 
4546e91fa0a1SMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4547e91fa0a1SMatthew G. Knepley     while (qEnd > qStart) {
45481690c2aeSBarry Smith       PetscInt sMin = PETSC_INT_MAX;
45491690c2aeSBarry Smith       PetscInt sMax = PETSC_INT_MIN;
4550e91fa0a1SMatthew G. Knepley 
4551e91fa0a1SMatthew G. Knepley       for (PetscInt q = qStart; q < qEnd; ++q) {
4552e91fa0a1SMatthew G. Knepley         const PetscInt *support;
4553e91fa0a1SMatthew G. Knepley         PetscInt        supportSize;
4554e91fa0a1SMatthew G. Knepley 
4555e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4556e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, q, &support));
4557e91fa0a1SMatthew G. Knepley         for (PetscInt s = 0; s < supportSize; ++s) {
4558e91fa0a1SMatthew G. Knepley           sMin = PetscMin(support[s], sMin);
4559e91fa0a1SMatthew G. Knepley           sMax = PetscMax(support[s], sMax);
4560e91fa0a1SMatthew G. Knepley         }
4561e91fa0a1SMatthew G. Knepley       }
4562e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetNumValues(label, &level));
4563e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4564e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4565e91fa0a1SMatthew G. Knepley     }
4566e91fa0a1SMatthew G. Knepley   }
4567e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4568e91fa0a1SMatthew G. Knepley }
4569e91fa0a1SMatthew G. Knepley 
4570552f7358SJed Brown /*@
4571a4e35b19SJacob Faibussowitsch   DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4572552f7358SJed Brown 
457320f4b53cSBarry Smith   Collective
4574552f7358SJed Brown 
4575552f7358SJed Brown   Input Parameter:
457660225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4577552f7358SJed Brown 
4578a1cb98faSBarry Smith   Level: beginner
4579552f7358SJed Brown 
4580552f7358SJed Brown   Notes:
4581a4e35b19SJacob Faibussowitsch   The strata group all points of the same grade, and this function calculates the strata. This
4582a4e35b19SJacob Faibussowitsch   grade can be seen as the height (or depth) of the point in the DAG.
4583a4e35b19SJacob Faibussowitsch 
4584a4e35b19SJacob Faibussowitsch   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4585a4e35b19SJacob Faibussowitsch   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4586a1cb98faSBarry Smith   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4587b1bb481bSMatthew 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
4588a1cb98faSBarry Smith   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4589a1cb98faSBarry Smith   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4590a1cb98faSBarry Smith   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4591552f7358SJed Brown 
4592b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4593b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4594b1bb481bSMatthew 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
4595b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4596a1cb98faSBarry Smith .vb
4597a1cb98faSBarry Smith   cone(c0) = {e0, v2}
4598a1cb98faSBarry Smith   cone(e0) = {v0, v1}
4599a1cb98faSBarry Smith .ve
4600a1cb98faSBarry Smith   If `DMPlexStratify()` is run on this mesh, it will give depths
4601a1cb98faSBarry Smith .vb
4602a1cb98faSBarry Smith    depth 0 = {v0, v1, v2}
4603a1cb98faSBarry Smith    depth 1 = {e0, c0}
4604a1cb98faSBarry Smith .ve
4605b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4606b1bb481bSMatthew Knepley 
4607a1cb98faSBarry Smith   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4608552f7358SJed Brown 
46091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4610552f7358SJed Brown @*/
4611d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4612d71ae5a4SJacob Faibussowitsch {
4613df0420ecSMatthew G. Knepley   DM_Plex  *mesh = (DM_Plex *)dm->data;
4614aa50250dSMatthew G. Knepley   DMLabel   label;
4615e91fa0a1SMatthew G. Knepley   PetscBool flg = PETSC_FALSE;
4616552f7358SJed Brown 
4617552f7358SJed Brown   PetscFunctionBegin;
4618552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
46199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4620277ea44aSLisandro Dalcin 
4621e91fa0a1SMatthew G. Knepley   // Create depth label
4622d28dd301SMatthew G. Knepley   PetscCall(DMRemoveLabel(dm, "depth", NULL));
46239566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
46249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4625277ea44aSLisandro Dalcin 
4626e91fa0a1SMatthew G. Knepley   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4627e91fa0a1SMatthew G. Knepley   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4628e91fa0a1SMatthew G. Knepley   else PetscCall(DMPlexStratify_Topological_Private(dm, label));
4629552f7358SJed Brown 
4630bf4602e4SToby Isaac   { /* just in case there is an empty process */
4631bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4632bf4602e4SToby Isaac 
46339566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
4634462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
463548a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4636bf4602e4SToby Isaac   }
46379566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
46389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
46393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4640552f7358SJed Brown }
4641552f7358SJed Brown 
4642d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4643d71ae5a4SJacob Faibussowitsch {
4644412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4645412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
46465e2c5519SMatthew G. Knepley   PetscBool      preferTensor;
4647ba2698f1SMatthew G. Knepley 
4648412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
46499566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
46509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
46519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
46525e2c5519SMatthew G. Knepley   PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor));
4653ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4654ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4655ba2698f1SMatthew G. Knepley     switch (pdepth) {
4656d71ae5a4SJacob Faibussowitsch     case 0:
4657d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4658d71ae5a4SJacob Faibussowitsch       break;
4659ba2698f1SMatthew G. Knepley     case 1:
4660ba2698f1SMatthew G. Knepley       switch (coneSize) {
4661d71ae5a4SJacob Faibussowitsch       case 2:
4662d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4663d71ae5a4SJacob Faibussowitsch         break;
4664d71ae5a4SJacob Faibussowitsch       case 3:
4665d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4666d71ae5a4SJacob Faibussowitsch         break;
4667ba2698f1SMatthew G. Knepley       case 4:
4668ba2698f1SMatthew G. Knepley         switch (dim) {
4669d71ae5a4SJacob Faibussowitsch         case 2:
4670d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4671d71ae5a4SJacob Faibussowitsch           break;
4672d71ae5a4SJacob Faibussowitsch         case 3:
4673d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4674d71ae5a4SJacob Faibussowitsch           break;
4675d71ae5a4SJacob Faibussowitsch         default:
4676d71ae5a4SJacob Faibussowitsch           break;
4677ba2698f1SMatthew G. Knepley         }
4678ba2698f1SMatthew G. Knepley         break;
4679d71ae5a4SJacob Faibussowitsch       case 5:
4680d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4681d71ae5a4SJacob Faibussowitsch         break;
4682d71ae5a4SJacob Faibussowitsch       case 6:
46835e2c5519SMatthew G. Knepley         ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM;
4684d71ae5a4SJacob Faibussowitsch         break;
4685d71ae5a4SJacob Faibussowitsch       case 8:
4686d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4687d71ae5a4SJacob Faibussowitsch         break;
4688d71ae5a4SJacob Faibussowitsch       default:
4689d71ae5a4SJacob Faibussowitsch         break;
4690ba2698f1SMatthew G. Knepley       }
4691ba2698f1SMatthew G. Knepley     }
4692ba2698f1SMatthew G. Knepley   } else {
4693ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4694ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4695ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4696ba2698f1SMatthew G. Knepley       switch (dim) {
4697ba2698f1SMatthew G. Knepley       case 1:
4698ba2698f1SMatthew G. Knepley         switch (coneSize) {
4699d71ae5a4SJacob Faibussowitsch         case 2:
4700d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4701d71ae5a4SJacob Faibussowitsch           break;
4702d71ae5a4SJacob Faibussowitsch         default:
4703d71ae5a4SJacob Faibussowitsch           break;
4704ba2698f1SMatthew G. Knepley         }
4705ba2698f1SMatthew G. Knepley         break;
4706ba2698f1SMatthew G. Knepley       case 2:
4707ba2698f1SMatthew G. Knepley         switch (coneSize) {
4708d71ae5a4SJacob Faibussowitsch         case 3:
4709d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4710d71ae5a4SJacob Faibussowitsch           break;
4711d71ae5a4SJacob Faibussowitsch         case 4:
4712d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4713d71ae5a4SJacob Faibussowitsch           break;
4714d71ae5a4SJacob Faibussowitsch         default:
4715d71ae5a4SJacob Faibussowitsch           break;
4716ba2698f1SMatthew G. Knepley         }
4717ba2698f1SMatthew G. Knepley         break;
4718ba2698f1SMatthew G. Knepley       case 3:
4719ba2698f1SMatthew G. Knepley         switch (coneSize) {
4720d71ae5a4SJacob Faibussowitsch         case 4:
4721d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4722d71ae5a4SJacob Faibussowitsch           break;
47239371c9d4SSatish Balay         case 5: {
4724da9060c4SMatthew G. Knepley           const PetscInt *cone;
4725da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4726da9060c4SMatthew G. Knepley 
47279566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
47289566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4729da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4730d71ae5a4SJacob Faibussowitsch           case 3:
47315e2c5519SMatthew G. Knepley             ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM;
4732d71ae5a4SJacob Faibussowitsch             break;
4733d71ae5a4SJacob Faibussowitsch           case 4:
4734d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4735d71ae5a4SJacob Faibussowitsch             break;
4736da9060c4SMatthew G. Knepley           }
47379371c9d4SSatish Balay         } break;
4738d71ae5a4SJacob Faibussowitsch         case 6:
4739d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4740d71ae5a4SJacob Faibussowitsch           break;
4741d71ae5a4SJacob Faibussowitsch         default:
4742d71ae5a4SJacob Faibussowitsch           break;
4743ba2698f1SMatthew G. Knepley         }
4744ba2698f1SMatthew G. Knepley         break;
4745d71ae5a4SJacob Faibussowitsch       default:
4746d71ae5a4SJacob Faibussowitsch         break;
4747ba2698f1SMatthew G. Knepley       }
4748ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4749ba2698f1SMatthew G. Knepley       switch (coneSize) {
4750d71ae5a4SJacob Faibussowitsch       case 2:
4751d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4752d71ae5a4SJacob Faibussowitsch         break;
4753d71ae5a4SJacob Faibussowitsch       case 3:
4754d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4755d71ae5a4SJacob Faibussowitsch         break;
4756d71ae5a4SJacob Faibussowitsch       case 4:
4757d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4758d71ae5a4SJacob Faibussowitsch         break;
4759d71ae5a4SJacob Faibussowitsch       default:
4760d71ae5a4SJacob Faibussowitsch         break;
4761ba2698f1SMatthew G. Knepley       }
4762ba2698f1SMatthew G. Knepley     }
4763ba2698f1SMatthew G. Knepley   }
4764412e9a14SMatthew G. Knepley   *pt = ct;
47653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4766ba2698f1SMatthew G. Knepley }
4767412e9a14SMatthew G. Knepley 
4768412e9a14SMatthew G. Knepley /*@
4769412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4770412e9a14SMatthew G. Knepley 
477120f4b53cSBarry Smith   Collective
4772412e9a14SMatthew G. Knepley 
4773412e9a14SMatthew G. Knepley   Input Parameter:
477460225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4775412e9a14SMatthew G. Knepley 
4776412e9a14SMatthew G. Knepley   Level: developer
4777412e9a14SMatthew G. Knepley 
4778a1cb98faSBarry Smith   Note:
4779a1cb98faSBarry Smith   This function is normally called automatically when a cell type is requested. It creates an
4780a1cb98faSBarry Smith   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4781a1cb98faSBarry Smith   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4782412e9a14SMatthew G. Knepley 
4783a1cb98faSBarry Smith   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4784a1cb98faSBarry Smith 
47851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4786412e9a14SMatthew G. Knepley @*/
4787d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4788d71ae5a4SJacob Faibussowitsch {
4789412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4790412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4791412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4792412e9a14SMatthew G. Knepley 
4793412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4794412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4795412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
47969566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
47979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
47989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
479921027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
480021027e53SStefano Zampini   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4801412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4802327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4803412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4804412e9a14SMatthew G. Knepley 
48059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
48069566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4807841fc1b7SMatthew G. Knepley     PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]);
48089566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
48096497c311SBarry Smith     mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
4810412e9a14SMatthew G. Knepley   }
48119566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
48129566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
48133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4814ba2698f1SMatthew G. Knepley }
4815ba2698f1SMatthew G. Knepley 
4816552f7358SJed Brown /*@C
4817552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4818552f7358SJed Brown 
4819552f7358SJed Brown   Not Collective
4820552f7358SJed Brown 
4821552f7358SJed Brown   Input Parameters:
4822a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4823552f7358SJed Brown . numPoints - The number of input points for the join
4824552f7358SJed Brown - points    - The input points
4825552f7358SJed Brown 
4826552f7358SJed Brown   Output Parameters:
4827552f7358SJed Brown + numCoveredPoints - The number of points in the join
4828552f7358SJed Brown - coveredPoints    - The points in the join
4829552f7358SJed Brown 
4830552f7358SJed Brown   Level: intermediate
4831552f7358SJed Brown 
4832a1cb98faSBarry Smith   Note:
4833a1cb98faSBarry Smith   Currently, this is restricted to a single level join
4834552f7358SJed Brown 
483560225df5SJacob Faibussowitsch   Fortran Notes:
48362c9a7b26SBarry Smith   `converedPoints` must be declared with
48372c9a7b26SBarry Smith .vb
48382c9a7b26SBarry Smith   PetscInt, pointer :: coveredPints(:)
48392c9a7b26SBarry Smith .ve
48402c9a7b26SBarry Smith 
48411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4842552f7358SJed Brown @*/
48435d83a8b1SBarry Smith PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4844d71ae5a4SJacob Faibussowitsch {
4845552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4846552f7358SJed Brown   PetscInt *join[2];
4847552f7358SJed Brown   PetscInt  joinSize, i = 0;
4848552f7358SJed Brown   PetscInt  dof, off, p, c, m;
48496302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4850552f7358SJed Brown 
4851552f7358SJed Brown   PetscFunctionBegin;
4852552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48534f572ea9SToby Isaac   PetscAssertPointer(points, 3);
48544f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
48554f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
48566302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
48576302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
48586302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4859552f7358SJed Brown   /* Copy in support of first point */
48609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
48619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4862ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4863552f7358SJed Brown   /* Check each successive support */
4864552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4865552f7358SJed Brown     PetscInt newJoinSize = 0;
4866552f7358SJed Brown 
48679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
48689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4869552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4870552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4871552f7358SJed Brown 
4872552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4873552f7358SJed Brown         if (point == join[i][m]) {
4874552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4875552f7358SJed Brown           break;
4876552f7358SJed Brown         }
4877552f7358SJed Brown       }
4878552f7358SJed Brown     }
4879552f7358SJed Brown     joinSize = newJoinSize;
4880552f7358SJed Brown     i        = 1 - i;
4881552f7358SJed Brown   }
4882552f7358SJed Brown   *numCoveredPoints = joinSize;
4883552f7358SJed Brown   *coveredPoints    = join[i];
48846302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
48853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4886552f7358SJed Brown }
4887552f7358SJed Brown 
4888552f7358SJed Brown /*@C
48892c9a7b26SBarry Smith   DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()`
4890552f7358SJed Brown 
4891552f7358SJed Brown   Not Collective
4892552f7358SJed Brown 
4893552f7358SJed Brown   Input Parameters:
4894a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4895552f7358SJed Brown . numPoints - The number of input points for the join
4896552f7358SJed Brown - points    - The input points
4897552f7358SJed Brown 
4898552f7358SJed Brown   Output Parameters:
4899552f7358SJed Brown + numCoveredPoints - The number of points in the join
4900552f7358SJed Brown - coveredPoints    - The points in the join
4901552f7358SJed Brown 
4902552f7358SJed Brown   Level: intermediate
4903552f7358SJed Brown 
490460225df5SJacob Faibussowitsch   Fortran Notes:
4905feaf08eaSBarry Smith   `converedPoints` must be declared with
4906feaf08eaSBarry Smith .vb
4907feaf08eaSBarry Smith   PetscInt, pointer :: coveredPoints(:)
4908feaf08eaSBarry Smith .ve
4909feaf08eaSBarry Smith 
4910feaf08eaSBarry Smith   Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed
4911a1cb98faSBarry Smith 
49121cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4913552f7358SJed Brown @*/
49142c9a7b26SBarry Smith PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4915d71ae5a4SJacob Faibussowitsch {
4916552f7358SJed Brown   PetscFunctionBegin;
4917552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49184f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
49194f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
49204f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
49219566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4922d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
49233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4924552f7358SJed Brown }
4925552f7358SJed Brown 
4926552f7358SJed Brown /*@C
4927552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4928552f7358SJed Brown 
4929552f7358SJed Brown   Not Collective
4930552f7358SJed Brown 
4931552f7358SJed Brown   Input Parameters:
4932a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4933552f7358SJed Brown . numPoints - The number of input points for the join
49342c9a7b26SBarry Smith - points    - The input points, its length is `numPoints`
4935552f7358SJed Brown 
4936552f7358SJed Brown   Output Parameters:
4937552f7358SJed Brown + numCoveredPoints - The number of points in the join
49382c9a7b26SBarry Smith - coveredPoints    - The points in the join, its length is `numCoveredPoints`
4939552f7358SJed Brown 
4940552f7358SJed Brown   Level: intermediate
4941552f7358SJed Brown 
494260225df5SJacob Faibussowitsch   Fortran Notes:
49432c9a7b26SBarry Smith .vb
49442c9a7b26SBarry Smith   PetscInt, pointer :: coveredPints(:)
49452c9a7b26SBarry Smith .ve
49462c9a7b26SBarry Smith 
49471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4948552f7358SJed Brown @*/
49495d83a8b1SBarry Smith PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4950d71ae5a4SJacob Faibussowitsch {
4951552f7358SJed Brown   PetscInt *offsets, **closures;
4952552f7358SJed Brown   PetscInt *join[2];
4953552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
495424c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4955552f7358SJed Brown 
4956552f7358SJed Brown   PetscFunctionBegin;
4957552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49584f572ea9SToby Isaac   PetscAssertPointer(points, 3);
49594f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
49604f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4961552f7358SJed Brown 
49629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
49639566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
49649566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
49656302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
496624c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
49679566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
49689566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4969552f7358SJed Brown 
4970552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4971552f7358SJed Brown     PetscInt closureSize;
4972552f7358SJed Brown 
49739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
49740d644c17SKarl Rupp 
4975552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4976552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4977552f7358SJed Brown       PetscInt pStart, pEnd, i;
4978552f7358SJed Brown 
49799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4980552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4981552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4982552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4983552f7358SJed Brown           break;
4984552f7358SJed Brown         }
4985552f7358SJed Brown       }
4986552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4987552f7358SJed Brown     }
498863a3b9bcSJacob 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);
4989552f7358SJed Brown   }
4990552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4991552f7358SJed Brown     PetscInt dof;
4992552f7358SJed Brown 
4993552f7358SJed Brown     /* Copy in support of first point */
4994552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4995ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4996552f7358SJed Brown     /* Check each successive cone */
4997552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4998552f7358SJed Brown       PetscInt newJoinSize = 0;
4999552f7358SJed Brown 
5000552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
5001552f7358SJed Brown       for (c = 0; c < dof; ++c) {
5002552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
5003552f7358SJed Brown 
5004552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
5005552f7358SJed Brown           if (point == join[i][m]) {
5006552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
5007552f7358SJed Brown             break;
5008552f7358SJed Brown           }
5009552f7358SJed Brown         }
5010552f7358SJed Brown       }
5011552f7358SJed Brown       joinSize = newJoinSize;
5012552f7358SJed Brown       i        = 1 - i;
5013552f7358SJed Brown     }
5014552f7358SJed Brown     if (joinSize) break;
5015552f7358SJed Brown   }
5016552f7358SJed Brown   *numCoveredPoints = joinSize;
5017552f7358SJed Brown   *coveredPoints    = join[i];
501848a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
50199566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
50209566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
50216302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
50223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5023552f7358SJed Brown }
5024552f7358SJed Brown 
5025552f7358SJed Brown /*@C
5026552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
5027552f7358SJed Brown 
5028552f7358SJed Brown   Not Collective
5029552f7358SJed Brown 
5030552f7358SJed Brown   Input Parameters:
5031a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5032552f7358SJed Brown . numPoints - The number of input points for the meet
50332c9a7b26SBarry Smith - points    - The input points, of length `numPoints`
5034552f7358SJed Brown 
5035552f7358SJed Brown   Output Parameters:
503660225df5SJacob Faibussowitsch + numCoveringPoints - The number of points in the meet
50372c9a7b26SBarry Smith - coveringPoints    - The points in the meet, of length `numCoveringPoints`
5038552f7358SJed Brown 
5039552f7358SJed Brown   Level: intermediate
5040552f7358SJed Brown 
5041a1cb98faSBarry Smith   Note:
5042a1cb98faSBarry Smith   Currently, this is restricted to a single level meet
5043552f7358SJed Brown 
5044feaf08eaSBarry Smith   Fortran Note:
50452c9a7b26SBarry Smith   `coveringPoints` must be declared with
50462c9a7b26SBarry Smith .vb
50472c9a7b26SBarry Smith   PetscInt, pointer :: coveringPoints(:)
50482c9a7b26SBarry Smith .ve
50492c9a7b26SBarry Smith 
50501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5051552f7358SJed Brown @*/
50525d83a8b1SBarry Smith PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[])
5053d71ae5a4SJacob Faibussowitsch {
5054552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
5055552f7358SJed Brown   PetscInt *meet[2];
5056552f7358SJed Brown   PetscInt  meetSize, i = 0;
5057552f7358SJed Brown   PetscInt  dof, off, p, c, m;
50586302a7fbSVaclav Hapla   PetscInt  maxConeSize;
5059552f7358SJed Brown 
5060552f7358SJed Brown   PetscFunctionBegin;
5061552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50624f572ea9SToby Isaac   PetscAssertPointer(points, 3);
50634f572ea9SToby Isaac   PetscAssertPointer(numCoveringPoints, 4);
50644f572ea9SToby Isaac   PetscAssertPointer(coveringPoints, 5);
50656302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
50666302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
50676302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
5068552f7358SJed Brown   /* Copy in cone of first point */
50699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
50709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
5071ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
5072552f7358SJed Brown   /* Check each successive cone */
5073552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
5074552f7358SJed Brown     PetscInt newMeetSize = 0;
5075552f7358SJed Brown 
50769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
50779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
5078552f7358SJed Brown     for (c = 0; c < dof; ++c) {
5079552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
5080552f7358SJed Brown 
5081552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
5082552f7358SJed Brown         if (point == meet[i][m]) {
5083552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
5084552f7358SJed Brown           break;
5085552f7358SJed Brown         }
5086552f7358SJed Brown       }
5087552f7358SJed Brown     }
5088552f7358SJed Brown     meetSize = newMeetSize;
5089552f7358SJed Brown     i        = 1 - i;
5090552f7358SJed Brown   }
5091552f7358SJed Brown   *numCoveringPoints = meetSize;
5092552f7358SJed Brown   *coveringPoints    = meet[i];
50936302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
50943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5095552f7358SJed Brown }
5096552f7358SJed Brown 
5097552f7358SJed Brown /*@C
50982c9a7b26SBarry Smith   DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()`
5099552f7358SJed Brown 
5100552f7358SJed Brown   Not Collective
5101552f7358SJed Brown 
5102552f7358SJed Brown   Input Parameters:
5103a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5104552f7358SJed Brown . numPoints - The number of input points for the meet
5105552f7358SJed Brown - points    - The input points
5106552f7358SJed Brown 
5107552f7358SJed Brown   Output Parameters:
5108552f7358SJed Brown + numCoveredPoints - The number of points in the meet
5109552f7358SJed Brown - coveredPoints    - The points in the meet
5110552f7358SJed Brown 
5111552f7358SJed Brown   Level: intermediate
5112552f7358SJed Brown 
51131cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
5114552f7358SJed Brown @*/
51155d83a8b1SBarry Smith PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5116d71ae5a4SJacob Faibussowitsch {
5117552f7358SJed Brown   PetscFunctionBegin;
5118552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51194f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
51204f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
51214f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
51229566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
5123d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
51243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5125552f7358SJed Brown }
5126552f7358SJed Brown 
5127552f7358SJed Brown /*@C
5128552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
5129552f7358SJed Brown 
5130552f7358SJed Brown   Not Collective
5131552f7358SJed Brown 
5132552f7358SJed Brown   Input Parameters:
5133a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5134552f7358SJed Brown . numPoints - The number of input points for the meet
51352c9a7b26SBarry Smith - points    - The input points, of length  `numPoints`
5136552f7358SJed Brown 
5137552f7358SJed Brown   Output Parameters:
5138552f7358SJed Brown + numCoveredPoints - The number of points in the meet
51392c9a7b26SBarry Smith - coveredPoints    - The points in the meet, of length  `numCoveredPoints`
5140552f7358SJed Brown 
5141552f7358SJed Brown   Level: intermediate
5142552f7358SJed Brown 
514360225df5SJacob Faibussowitsch   Fortran Notes:
5144feaf08eaSBarry Smith   `coveredPoints` must be declared with
51452c9a7b26SBarry Smith .vb
51462c9a7b26SBarry Smith   PetscInt, pointer :: coveredPoints(:)
51472c9a7b26SBarry Smith .ve
51482c9a7b26SBarry Smith 
51491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5150552f7358SJed Brown @*/
51515d83a8b1SBarry Smith PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5152d71ae5a4SJacob Faibussowitsch {
5153552f7358SJed Brown   PetscInt *offsets, **closures;
5154552f7358SJed Brown   PetscInt *meet[2];
5155552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
515624c766afSToby Isaac   PetscInt  p, h, c, m, mc;
5157552f7358SJed Brown 
5158552f7358SJed Brown   PetscFunctionBegin;
5159552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51604f572ea9SToby Isaac   PetscAssertPointer(points, 3);
51614f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
51624f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
5163552f7358SJed Brown 
51649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
51659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
51669566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
51676302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
516824c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
51699566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
51709566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
5171552f7358SJed Brown 
5172552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
5173552f7358SJed Brown     PetscInt closureSize;
5174552f7358SJed Brown 
51759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
51760d644c17SKarl Rupp 
5177552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
5178552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
5179552f7358SJed Brown       PetscInt pStart, pEnd, i;
5180552f7358SJed Brown 
51819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
5182552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
5183552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
5184552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
5185552f7358SJed Brown           break;
5186552f7358SJed Brown         }
5187552f7358SJed Brown       }
5188552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
5189552f7358SJed Brown     }
519063a3b9bcSJacob 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);
5191552f7358SJed Brown   }
5192552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
5193552f7358SJed Brown     PetscInt dof;
5194552f7358SJed Brown 
5195552f7358SJed Brown     /* Copy in cone of first point */
5196552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
5197ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
5198552f7358SJed Brown     /* Check each successive cone */
5199552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
5200552f7358SJed Brown       PetscInt newMeetSize = 0;
5201552f7358SJed Brown 
5202552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
5203552f7358SJed Brown       for (c = 0; c < dof; ++c) {
5204552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
5205552f7358SJed Brown 
5206552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
5207552f7358SJed Brown           if (point == meet[i][m]) {
5208552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
5209552f7358SJed Brown             break;
5210552f7358SJed Brown           }
5211552f7358SJed Brown         }
5212552f7358SJed Brown       }
5213552f7358SJed Brown       meetSize = newMeetSize;
5214552f7358SJed Brown       i        = 1 - i;
5215552f7358SJed Brown     }
5216552f7358SJed Brown     if (meetSize) break;
5217552f7358SJed Brown   }
5218552f7358SJed Brown   *numCoveredPoints = meetSize;
5219552f7358SJed Brown   *coveredPoints    = meet[i];
522048a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
52219566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
52229566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
52236302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
52243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5225552f7358SJed Brown }
5226552f7358SJed Brown 
5227cc4c1da9SBarry Smith /*@
5228a1cb98faSBarry Smith   DMPlexEqual - Determine if two `DM` have the same topology
52294e3744c5SMatthew G. Knepley 
52304e3744c5SMatthew G. Knepley   Not Collective
52314e3744c5SMatthew G. Knepley 
52324e3744c5SMatthew G. Knepley   Input Parameters:
5233a1cb98faSBarry Smith + dmA - A `DMPLEX` object
5234a1cb98faSBarry Smith - dmB - A `DMPLEX` object
52354e3744c5SMatthew G. Knepley 
52362fe279fdSBarry Smith   Output Parameter:
5237a1cb98faSBarry Smith . equal - `PETSC_TRUE` if the topologies are identical
52384e3744c5SMatthew G. Knepley 
52394e3744c5SMatthew G. Knepley   Level: intermediate
52404e3744c5SMatthew G. Knepley 
5241a1cb98faSBarry Smith   Note:
52423c7db156SBarry Smith   We are not solving graph isomorphism, so we do not permute.
52434e3744c5SMatthew G. Knepley 
52441cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
52454e3744c5SMatthew G. Knepley @*/
5246d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5247d71ae5a4SJacob Faibussowitsch {
52484e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
52494e3744c5SMatthew G. Knepley 
52504e3744c5SMatthew G. Knepley   PetscFunctionBegin;
52514e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
52524e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
52534f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
52544e3744c5SMatthew G. Knepley 
52554e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
52569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
52579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
52583ba16761SJacob Faibussowitsch   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
52599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
52609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
52613ba16761SJacob Faibussowitsch   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
52624e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
52634e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
52644e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
52654e3744c5SMatthew G. Knepley 
52669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
52679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
52689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
52699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
52709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
52719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
52723ba16761SJacob Faibussowitsch     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
52734e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
52743ba16761SJacob Faibussowitsch       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
52753ba16761SJacob Faibussowitsch       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
52764e3744c5SMatthew G. Knepley     }
52779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
52789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
52799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
52809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
52813ba16761SJacob Faibussowitsch     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
52824e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
52833ba16761SJacob Faibussowitsch       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
52844e3744c5SMatthew G. Knepley     }
52854e3744c5SMatthew G. Knepley   }
52864e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
52873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52884e3744c5SMatthew G. Knepley }
52894e3744c5SMatthew G. Knepley 
5290cc4c1da9SBarry Smith /*@
52917cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
52927cd05799SMatthew G. Knepley 
52937cd05799SMatthew G. Knepley   Not Collective
52947cd05799SMatthew G. Knepley 
52957cd05799SMatthew G. Knepley   Input Parameters:
5296a1cb98faSBarry Smith + dm         - The `DMPLEX`
52977cd05799SMatthew G. Knepley . cellDim    - The cell dimension
52987cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
52997cd05799SMatthew G. Knepley 
53002fe279fdSBarry Smith   Output Parameter:
53017cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
53027cd05799SMatthew G. Knepley 
53037cd05799SMatthew G. Knepley   Level: developer
53047cd05799SMatthew G. Knepley 
5305a1cb98faSBarry Smith   Note:
53067cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
53077cd05799SMatthew G. Knepley 
53081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
53097cd05799SMatthew G. Knepley @*/
5310d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5311d71ae5a4SJacob Faibussowitsch {
531282f516ccSBarry Smith   MPI_Comm comm;
5313552f7358SJed Brown 
5314552f7358SJed Brown   PetscFunctionBegin;
53159566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
53164f572ea9SToby Isaac   PetscAssertPointer(numFaceVertices, 4);
5317552f7358SJed Brown   switch (cellDim) {
5318d71ae5a4SJacob Faibussowitsch   case 0:
5319d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
5320d71ae5a4SJacob Faibussowitsch     break;
5321d71ae5a4SJacob Faibussowitsch   case 1:
5322d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
5323d71ae5a4SJacob Faibussowitsch     break;
5324552f7358SJed Brown   case 2:
5325552f7358SJed Brown     switch (numCorners) {
532619436ca2SJed Brown     case 3:                 /* triangle */
532719436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5328552f7358SJed Brown       break;
532919436ca2SJed Brown     case 4:                 /* quadrilateral */
533019436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5331552f7358SJed Brown       break;
533219436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
533319436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5334552f7358SJed Brown       break;
533519436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
533619436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5337552f7358SJed Brown       break;
5338d71ae5a4SJacob Faibussowitsch     default:
5339d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5340552f7358SJed Brown     }
5341552f7358SJed Brown     break;
5342552f7358SJed Brown   case 3:
5343552f7358SJed Brown     switch (numCorners) {
534419436ca2SJed Brown     case 4:                 /* tetradehdron */
534519436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
5346552f7358SJed Brown       break;
534719436ca2SJed Brown     case 6:                 /* tet cohesive cells */
534819436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5349552f7358SJed Brown       break;
535019436ca2SJed Brown     case 8:                 /* hexahedron */
535119436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5352552f7358SJed Brown       break;
535319436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
535419436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5355552f7358SJed Brown       break;
535619436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
535719436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5358552f7358SJed Brown       break;
535919436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
536019436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5361552f7358SJed Brown       break;
536219436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
536319436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5364552f7358SJed Brown       break;
536519436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
536619436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
5367552f7358SJed Brown       break;
5368d71ae5a4SJacob Faibussowitsch     default:
5369d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5370552f7358SJed Brown     }
5371552f7358SJed Brown     break;
5372d71ae5a4SJacob Faibussowitsch   default:
5373d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5374552f7358SJed Brown   }
53753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5376552f7358SJed Brown }
5377552f7358SJed Brown 
5378552f7358SJed Brown /*@
5379a1cb98faSBarry Smith   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
5380552f7358SJed Brown 
5381552f7358SJed Brown   Not Collective
5382552f7358SJed Brown 
5383aa50250dSMatthew G. Knepley   Input Parameter:
5384a1cb98faSBarry Smith . dm - The `DMPLEX` object
5385552f7358SJed Brown 
5386aa50250dSMatthew G. Knepley   Output Parameter:
5387a1cb98faSBarry Smith . depthLabel - The `DMLabel` recording point depth
5388552f7358SJed Brown 
5389552f7358SJed Brown   Level: developer
5390552f7358SJed Brown 
53911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5392aa50250dSMatthew G. Knepley @*/
5393d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5394d71ae5a4SJacob Faibussowitsch {
5395aa50250dSMatthew G. Knepley   PetscFunctionBegin;
5396aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53974f572ea9SToby Isaac   PetscAssertPointer(depthLabel, 2);
5398c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
53993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5400aa50250dSMatthew G. Knepley }
5401aa50250dSMatthew G. Knepley 
5402aa50250dSMatthew G. Knepley /*@
5403aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5404aa50250dSMatthew G. Knepley 
5405aa50250dSMatthew G. Knepley   Not Collective
5406aa50250dSMatthew G. Knepley 
5407aa50250dSMatthew G. Knepley   Input Parameter:
5408a1cb98faSBarry Smith . dm - The `DMPLEX` object
5409aa50250dSMatthew G. Knepley 
5410aa50250dSMatthew G. Knepley   Output Parameter:
5411aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
5412aa50250dSMatthew G. Knepley 
5413aa50250dSMatthew G. Knepley   Level: developer
5414552f7358SJed Brown 
5415b1bb481bSMatthew Knepley   Notes:
5416a1cb98faSBarry Smith   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
5417a1cb98faSBarry Smith 
5418a1cb98faSBarry Smith   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
5419a1cb98faSBarry Smith 
5420dc287ab2SVaclav Hapla   An empty mesh gives -1.
5421b1bb481bSMatthew Knepley 
54221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5423552f7358SJed Brown @*/
5424d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5425d71ae5a4SJacob Faibussowitsch {
54269f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5427aa50250dSMatthew G. Knepley   DMLabel  label;
5428452349dbSMatthew G. Knepley   PetscInt d = -1;
5429552f7358SJed Brown 
5430552f7358SJed Brown   PetscFunctionBegin;
5431552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54324f572ea9SToby Isaac   PetscAssertPointer(depth, 2);
54339f4ada15SMatthew G. Knepley   if (mesh->tr) {
54349f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
54359f4ada15SMatthew G. Knepley   } else {
54369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
5437452349dbSMatthew G. Knepley     // Allow missing depths
5438452349dbSMatthew G. Knepley     if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d));
5439452349dbSMatthew G. Knepley     *depth = d;
54409f4ada15SMatthew G. Knepley   }
54413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5442552f7358SJed Brown }
5443552f7358SJed Brown 
5444552f7358SJed Brown /*@
544520f4b53cSBarry Smith   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5446552f7358SJed Brown 
5447552f7358SJed Brown   Not Collective
5448552f7358SJed Brown 
5449552f7358SJed Brown   Input Parameters:
5450a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5451570fa34dSVaclav Hapla - depth - The requested depth
5452552f7358SJed Brown 
5453552f7358SJed Brown   Output Parameters:
545420f4b53cSBarry Smith + start - The first point at this `depth`
545520f4b53cSBarry Smith - end   - One beyond the last point at this `depth`
5456552f7358SJed Brown 
5457552f7358SJed Brown   Level: developer
5458552f7358SJed Brown 
5459a1cb98faSBarry Smith   Notes:
5460a1cb98faSBarry Smith   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5461a1cb98faSBarry Smith   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5462a1cb98faSBarry Smith   higher dimension, e.g., "edges".
5463a1cb98faSBarry Smith 
54642827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5465552f7358SJed Brown @*/
5466ce78bad3SBarry Smith PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end)
5467d71ae5a4SJacob Faibussowitsch {
54689f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5469aa50250dSMatthew G. Knepley   DMLabel  label;
547063d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
5471552f7358SJed Brown 
5472552f7358SJed Brown   PetscFunctionBegin;
5473552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54749371c9d4SSatish Balay   if (start) {
54754f572ea9SToby Isaac     PetscAssertPointer(start, 3);
54769371c9d4SSatish Balay     *start = 0;
54779371c9d4SSatish Balay   }
54789371c9d4SSatish Balay   if (end) {
54794f572ea9SToby Isaac     PetscAssertPointer(end, 4);
54809371c9d4SSatish Balay     *end = 0;
54819371c9d4SSatish Balay   }
54829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
54833ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5484570fa34dSVaclav Hapla   if (depth < 0) {
548563d1a920SMatthew G. Knepley     if (start) *start = pStart;
548663d1a920SMatthew G. Knepley     if (end) *end = pEnd;
54873ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5488552f7358SJed Brown   }
54899f4ada15SMatthew G. Knepley   if (mesh->tr) {
54909f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
54919f4ada15SMatthew G. Knepley   } else {
54929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
549328b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5494570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
54959f4ada15SMatthew G. Knepley   }
54963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5497552f7358SJed Brown }
5498552f7358SJed Brown 
5499552f7358SJed Brown /*@
550020f4b53cSBarry Smith   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5501552f7358SJed Brown 
5502552f7358SJed Brown   Not Collective
5503552f7358SJed Brown 
5504552f7358SJed Brown   Input Parameters:
5505a1cb98faSBarry Smith + dm     - The `DMPLEX` object
5506570fa34dSVaclav Hapla - height - The requested height
5507552f7358SJed Brown 
5508552f7358SJed Brown   Output Parameters:
550920f4b53cSBarry Smith + start - The first point at this `height`
551020f4b53cSBarry Smith - end   - One beyond the last point at this `height`
5511552f7358SJed Brown 
5512552f7358SJed Brown   Level: developer
5513552f7358SJed Brown 
5514a1cb98faSBarry Smith   Notes:
5515a1cb98faSBarry Smith   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5516a1cb98faSBarry Smith   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5517a1cb98faSBarry Smith   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5518a1cb98faSBarry Smith 
55192827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5520552f7358SJed Brown @*/
5521ce78bad3SBarry Smith PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end)
5522d71ae5a4SJacob Faibussowitsch {
5523aa50250dSMatthew G. Knepley   DMLabel  label;
552463d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5525552f7358SJed Brown 
5526552f7358SJed Brown   PetscFunctionBegin;
5527552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55289371c9d4SSatish Balay   if (start) {
55294f572ea9SToby Isaac     PetscAssertPointer(start, 3);
55309371c9d4SSatish Balay     *start = 0;
55319371c9d4SSatish Balay   }
55329371c9d4SSatish Balay   if (end) {
55334f572ea9SToby Isaac     PetscAssertPointer(end, 4);
55349371c9d4SSatish Balay     *end = 0;
55359371c9d4SSatish Balay   }
55369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
55373ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5538570fa34dSVaclav Hapla   if (height < 0) {
553963d1a920SMatthew G. Knepley     if (start) *start = pStart;
554063d1a920SMatthew G. Knepley     if (end) *end = pEnd;
55413ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5542552f7358SJed Brown   }
55439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
554459e4dc13SStefano Zampini   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
554559e4dc13SStefano Zampini   else PetscCall(DMGetDimension(dm, &depth));
554659e4dc13SStefano Zampini   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
554759e4dc13SStefano Zampini   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
55483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5549552f7358SJed Brown }
5550552f7358SJed Brown 
5551ba2698f1SMatthew G. Knepley /*@
555220f4b53cSBarry Smith   DMPlexGetPointDepth - Get the `depth` of a given point
5553ba2698f1SMatthew G. Knepley 
5554ba2698f1SMatthew G. Knepley   Not Collective
5555ba2698f1SMatthew G. Knepley 
5556d8d19677SJose E. Roman   Input Parameters:
5557a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5558ba2698f1SMatthew G. Knepley - point - The point
5559ba2698f1SMatthew G. Knepley 
5560ba2698f1SMatthew G. Knepley   Output Parameter:
556120f4b53cSBarry Smith . depth - The depth of the `point`
5562ba2698f1SMatthew G. Knepley 
5563ba2698f1SMatthew G. Knepley   Level: intermediate
5564ba2698f1SMatthew G. Knepley 
55651cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5566ba2698f1SMatthew G. Knepley @*/
5567d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5568d71ae5a4SJacob Faibussowitsch {
5569ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5570ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55714f572ea9SToby Isaac   PetscAssertPointer(depth, 3);
55729566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
55733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5574ba2698f1SMatthew G. Knepley }
5575ba2698f1SMatthew G. Knepley 
5576ba2698f1SMatthew G. Knepley /*@
557720f4b53cSBarry Smith   DMPlexGetPointHeight - Get the `height` of a given point
55780c0a32dcSVaclav Hapla 
55790c0a32dcSVaclav Hapla   Not Collective
55800c0a32dcSVaclav Hapla 
5581d8d19677SJose E. Roman   Input Parameters:
5582a1cb98faSBarry Smith + dm    - The `DMPLEX` object
55830c0a32dcSVaclav Hapla - point - The point
55840c0a32dcSVaclav Hapla 
55850c0a32dcSVaclav Hapla   Output Parameter:
558620f4b53cSBarry Smith . height - The height of the `point`
55870c0a32dcSVaclav Hapla 
55880c0a32dcSVaclav Hapla   Level: intermediate
55890c0a32dcSVaclav Hapla 
55901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
55910c0a32dcSVaclav Hapla @*/
5592d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5593d71ae5a4SJacob Faibussowitsch {
55940c0a32dcSVaclav Hapla   PetscInt n, pDepth;
55950c0a32dcSVaclav Hapla 
55960c0a32dcSVaclav Hapla   PetscFunctionBegin;
55970c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55984f572ea9SToby Isaac   PetscAssertPointer(height, 3);
55999566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
56009566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
56010c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
56023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56030c0a32dcSVaclav Hapla }
56040c0a32dcSVaclav Hapla 
56050c0a32dcSVaclav Hapla /*@
5606a1cb98faSBarry Smith   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5607ba2698f1SMatthew G. Knepley 
5608ba2698f1SMatthew G. Knepley   Not Collective
5609ba2698f1SMatthew G. Knepley 
5610ba2698f1SMatthew G. Knepley   Input Parameter:
5611a1cb98faSBarry Smith . dm - The `DMPLEX` object
5612ba2698f1SMatthew G. Knepley 
5613ba2698f1SMatthew G. Knepley   Output Parameter:
5614a1cb98faSBarry Smith . celltypeLabel - The `DMLabel` recording cell polytope type
5615412e9a14SMatthew G. Knepley 
5616ba2698f1SMatthew G. Knepley   Level: developer
5617ba2698f1SMatthew G. Knepley 
5618a1cb98faSBarry Smith   Note:
5619a1cb98faSBarry Smith   This function will trigger automatica computation of cell types. This can be disabled by calling
5620a1cb98faSBarry Smith   `DMCreateLabel`(dm, "celltype") beforehand.
5621a1cb98faSBarry Smith 
56221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5623ba2698f1SMatthew G. Knepley @*/
5624d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5625d71ae5a4SJacob Faibussowitsch {
5626ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5627ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56284f572ea9SToby Isaac   PetscAssertPointer(celltypeLabel, 2);
56299566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5630ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
56313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5632ba2698f1SMatthew G. Knepley }
5633ba2698f1SMatthew G. Knepley 
5634ba2698f1SMatthew G. Knepley /*@
5635ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5636ba2698f1SMatthew G. Knepley 
5637ba2698f1SMatthew G. Knepley   Not Collective
5638ba2698f1SMatthew G. Knepley 
5639d8d19677SJose E. Roman   Input Parameters:
5640a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5641ba2698f1SMatthew G. Knepley - cell - The cell
5642ba2698f1SMatthew G. Knepley 
5643ba2698f1SMatthew G. Knepley   Output Parameter:
5644ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5645ba2698f1SMatthew G. Knepley 
5646ba2698f1SMatthew G. Knepley   Level: intermediate
5647ba2698f1SMatthew G. Knepley 
56481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5649ba2698f1SMatthew G. Knepley @*/
5650d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5651d71ae5a4SJacob Faibussowitsch {
56529f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5653ba2698f1SMatthew G. Knepley   DMLabel  label;
5654ba2698f1SMatthew G. Knepley   PetscInt ct;
5655ba2698f1SMatthew G. Knepley 
5656ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5657ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56584f572ea9SToby Isaac   PetscAssertPointer(celltype, 3);
56599f4ada15SMatthew G. Knepley   if (mesh->tr) {
56609f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
56619f4ada15SMatthew G. Knepley   } else {
566221027e53SStefano Zampini     PetscInt pStart, pEnd;
566321027e53SStefano Zampini 
566421027e53SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
566521027e53SStefano Zampini     if (!mesh->cellTypes) { /* XXX remove? optimize? */
566621027e53SStefano Zampini       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5667f4a55318SMatthew G. Knepley       if (pEnd <= pStart) {
5668f4a55318SMatthew G. Knepley         *celltype = DM_POLYTOPE_UNKNOWN;
5669f4a55318SMatthew G. Knepley         PetscFunctionReturn(PETSC_SUCCESS);
5670f4a55318SMatthew G. Knepley       }
567121027e53SStefano Zampini       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
567221027e53SStefano Zampini       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
567321027e53SStefano Zampini       for (PetscInt p = pStart; p < pEnd; p++) {
567421027e53SStefano Zampini         PetscCall(DMLabelGetValue(label, p, &ct));
56756497c311SBarry Smith         mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
567621027e53SStefano Zampini       }
567721027e53SStefano Zampini     }
567821027e53SStefano Zampini     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
567921027e53SStefano Zampini     if (PetscDefined(USE_DEBUG)) {
56809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
56819566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, cell, &ct));
568263a3b9bcSJacob Faibussowitsch       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5683936381afSPierre Jolivet       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
568421027e53SStefano Zampini     }
56859f4ada15SMatthew G. Knepley   }
56863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5687ba2698f1SMatthew G. Knepley }
5688ba2698f1SMatthew G. Knepley 
5689412e9a14SMatthew G. Knepley /*@
5690412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5691412e9a14SMatthew G. Knepley 
5692412e9a14SMatthew G. Knepley   Not Collective
5693412e9a14SMatthew G. Knepley 
5694412e9a14SMatthew G. Knepley   Input Parameters:
5695a1cb98faSBarry Smith + dm       - The `DMPLEX` object
5696412e9a14SMatthew G. Knepley . cell     - The cell
5697412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5698412e9a14SMatthew G. Knepley 
5699a1cb98faSBarry Smith   Level: advanced
5700a1cb98faSBarry Smith 
5701a1cb98faSBarry Smith   Note:
5702a1cb98faSBarry Smith   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5703412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5704412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5705db485b19SStefano Zampini   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5706412e9a14SMatthew G. Knepley 
57071cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5708412e9a14SMatthew G. Knepley @*/
5709d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5710d71ae5a4SJacob Faibussowitsch {
571121027e53SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
5712412e9a14SMatthew G. Knepley   DMLabel  label;
571321027e53SStefano Zampini   PetscInt pStart, pEnd;
5714412e9a14SMatthew G. Knepley 
5715412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5716412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
571721027e53SStefano Zampini   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
57189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
57199566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
572021027e53SStefano Zampini   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
57216497c311SBarry Smith   mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype;
57223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5723412e9a14SMatthew G. Knepley }
5724412e9a14SMatthew G. Knepley 
5725d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5726d71ae5a4SJacob Faibussowitsch {
5727c789d87fSToby Isaac   PetscSection section;
57283e922f36SToby Isaac   PetscInt     maxHeight;
5729dd4c3f67SMatthew G. Knepley   const char  *prefix;
5730552f7358SJed Brown 
5731552f7358SJed Brown   PetscFunctionBegin;
57329566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
5733dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5734dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5735dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
57369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
57379566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
57389566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
57399566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
57409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
57418f4c458bSMatthew G. Knepley 
57429566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
57439566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5744dd4c3f67SMatthew G. Knepley   (*cdm)->cloneOpts = PETSC_TRUE;
5745dd4c3f67SMatthew G. Knepley   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
57463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5747552f7358SJed Brown }
5748552f7358SJed Brown 
574999acd26cSksagiyam PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm)
575099acd26cSksagiyam {
575199acd26cSksagiyam   DM           cgcdm;
575299acd26cSksagiyam   PetscSection section;
575399acd26cSksagiyam   const char  *prefix;
575499acd26cSksagiyam 
575599acd26cSksagiyam   PetscFunctionBegin;
575699acd26cSksagiyam   PetscCall(DMGetCoordinateDM(dm, &cgcdm));
575799acd26cSksagiyam   PetscCall(DMClone(cgcdm, cdm));
575899acd26cSksagiyam   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
575999acd26cSksagiyam   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
576099acd26cSksagiyam   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_"));
576199acd26cSksagiyam   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
576299acd26cSksagiyam   PetscCall(DMSetLocalSection(*cdm, section));
576399acd26cSksagiyam   PetscCall(PetscSectionDestroy(&section));
576499acd26cSksagiyam   PetscCall(DMSetNumFields(*cdm, 1));
576599acd26cSksagiyam   PetscCall(DMCreateDS(*cdm));
576699acd26cSksagiyam   (*cdm)->cloneOpts = PETSC_TRUE;
576799acd26cSksagiyam   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
576899acd26cSksagiyam   PetscFunctionReturn(PETSC_SUCCESS);
576999acd26cSksagiyam }
577099acd26cSksagiyam 
5771d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5772d71ae5a4SJacob Faibussowitsch {
57736858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
57746858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5775f19dbd58SToby Isaac 
5776f19dbd58SToby Isaac   PetscFunctionBegin;
5777f19dbd58SToby Isaac   *field = NULL;
57789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
57799566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
57806858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
57816858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5782f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
57836858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
57846858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5785f19dbd58SToby Isaac   }
57863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5787f19dbd58SToby Isaac }
5788f19dbd58SToby Isaac 
5789cc4c1da9SBarry Smith /*@
57907cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
57917cd05799SMatthew G. Knepley 
57927cd05799SMatthew G. Knepley   Not Collective
57937cd05799SMatthew G. Knepley 
57942fe279fdSBarry Smith   Input Parameter:
5795a1cb98faSBarry Smith . dm - The `DMPLEX` object
57967cd05799SMatthew G. Knepley 
57977cd05799SMatthew G. Knepley   Output Parameter:
5798a1cb98faSBarry Smith . section - The `PetscSection` object
57997cd05799SMatthew G. Knepley 
58007cd05799SMatthew G. Knepley   Level: developer
58017cd05799SMatthew G. Knepley 
58021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
58037cd05799SMatthew G. Knepley @*/
5804d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5805d71ae5a4SJacob Faibussowitsch {
5806552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5807552f7358SJed Brown 
5808552f7358SJed Brown   PetscFunctionBegin;
5809552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5810552f7358SJed Brown   if (section) *section = mesh->coneSection;
58113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5812552f7358SJed Brown }
5813552f7358SJed Brown 
5814cc4c1da9SBarry Smith /*@
58157cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
58167cd05799SMatthew G. Knepley 
58177cd05799SMatthew G. Knepley   Not Collective
58187cd05799SMatthew G. Knepley 
58192fe279fdSBarry Smith   Input Parameter:
5820a1cb98faSBarry Smith . dm - The `DMPLEX` object
58217cd05799SMatthew G. Knepley 
58227cd05799SMatthew G. Knepley   Output Parameter:
5823a1cb98faSBarry Smith . section - The `PetscSection` object
58247cd05799SMatthew G. Knepley 
58257cd05799SMatthew G. Knepley   Level: developer
58267cd05799SMatthew G. Knepley 
58271cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
58287cd05799SMatthew G. Knepley @*/
5829d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5830d71ae5a4SJacob Faibussowitsch {
58318cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
58328cb4d582SMatthew G. Knepley 
58338cb4d582SMatthew G. Knepley   PetscFunctionBegin;
58348cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58358cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
58363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58378cb4d582SMatthew G. Knepley }
58388cb4d582SMatthew G. Knepley 
58397cd05799SMatthew G. Knepley /*@C
58407cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
58417cd05799SMatthew G. Knepley 
58427cd05799SMatthew G. Knepley   Not Collective
58437cd05799SMatthew G. Knepley 
58442fe279fdSBarry Smith   Input Parameter:
5845a1cb98faSBarry Smith . dm - The `DMPLEX` object
58467cd05799SMatthew G. Knepley 
58477cd05799SMatthew G. Knepley   Output Parameter:
58487cd05799SMatthew G. Knepley . cones - The cone for each point
58497cd05799SMatthew G. Knepley 
58507cd05799SMatthew G. Knepley   Level: developer
58517cd05799SMatthew G. Knepley 
58521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
58537cd05799SMatthew G. Knepley @*/
5854d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5855d71ae5a4SJacob Faibussowitsch {
5856552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5857552f7358SJed Brown 
5858552f7358SJed Brown   PetscFunctionBegin;
5859552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5860552f7358SJed Brown   if (cones) *cones = mesh->cones;
58613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5862552f7358SJed Brown }
5863552f7358SJed Brown 
58647cd05799SMatthew G. Knepley /*@C
58657cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
58667cd05799SMatthew G. Knepley 
58677cd05799SMatthew G. Knepley   Not Collective
58687cd05799SMatthew G. Knepley 
58692fe279fdSBarry Smith   Input Parameter:
5870a1cb98faSBarry Smith . dm - The `DMPLEX` object
58717cd05799SMatthew G. Knepley 
58727cd05799SMatthew G. Knepley   Output Parameter:
5873b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
58747cd05799SMatthew G. Knepley 
58757cd05799SMatthew G. Knepley   Level: developer
58767cd05799SMatthew G. Knepley 
5877b5a892a1SMatthew G. Knepley   Notes:
58782c9a7b26SBarry Smith   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points
58792c9a7b26SBarry Smith   as returned by `DMPlexGetConeOrientation()`.
5880b5a892a1SMatthew G. Knepley 
5881a1cb98faSBarry Smith   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5882b5a892a1SMatthew G. Knepley 
58831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
58847cd05799SMatthew G. Knepley @*/
5885d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5886d71ae5a4SJacob Faibussowitsch {
5887552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5888552f7358SJed Brown 
5889552f7358SJed Brown   PetscFunctionBegin;
5890552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5891552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
58923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5893552f7358SJed Brown }
5894552f7358SJed Brown 
58954ee01570SBarry Smith /* FEM Support */
5896552f7358SJed Brown 
5897d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5898d2b2dc1eSMatthew G. Knepley {
5899d2b2dc1eSMatthew G. Knepley   PetscInt depth;
5900d2b2dc1eSMatthew G. Knepley 
5901d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
5902d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
5903d2b2dc1eSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5904d2b2dc1eSMatthew G. Knepley   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5905d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
5906d2b2dc1eSMatthew G. Knepley }
5907d2b2dc1eSMatthew G. Knepley 
59085962854dSMatthew G. Knepley PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
59095962854dSMatthew G. Knepley {
59105962854dSMatthew G. Knepley   PetscInt depth;
59115962854dSMatthew G. Knepley 
59125962854dSMatthew G. Knepley   PetscFunctionBegin;
59135962854dSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
59145962854dSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
59155962854dSMatthew G. Knepley   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
59165962854dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
59175962854dSMatthew G. Knepley }
59185962854dSMatthew G. Knepley 
59199e8305c2SJed Brown /*
59209e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
59219e8305c2SJed Brown  representing a line in the section.
59229e8305c2SJed Brown */
59235f82726aSMatthew G. Knepley static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5924d71ae5a4SJacob Faibussowitsch {
5925e327e467SRezgar Shakeri   PetscObject  obj;
5926e327e467SRezgar Shakeri   PetscClassId id;
5927e327e467SRezgar Shakeri   PetscFE      fe = NULL;
5928e327e467SRezgar Shakeri 
59299e8305c2SJed Brown   PetscFunctionBeginHot;
59309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5931e327e467SRezgar Shakeri   PetscCall(DMGetField(dm, field, NULL, &obj));
5932e327e467SRezgar Shakeri   PetscCall(PetscObjectGetClassId(obj, &id));
5933e327e467SRezgar Shakeri   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;
5934e327e467SRezgar Shakeri 
5935e327e467SRezgar Shakeri   if (!fe) {
5936e327e467SRezgar Shakeri     /* Assume the full interpolated mesh is in the chart; lines in particular */
59379e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
59389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
59399e8305c2SJed Brown     *k = *k / *Nc + 1;
5940e327e467SRezgar Shakeri   } else {
5941e327e467SRezgar Shakeri     PetscInt       dual_space_size, dim;
59425f82726aSMatthew G. Knepley     PetscDualSpace dsp;
59435f82726aSMatthew G. Knepley 
5944e327e467SRezgar Shakeri     PetscCall(DMGetDimension(dm, &dim));
59455f82726aSMatthew G. Knepley     PetscCall(PetscFEGetDualSpace(fe, &dsp));
59465f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5947e327e467SRezgar Shakeri     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
59485f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
59495f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
59505f82726aSMatthew G. Knepley   }
59515f82726aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
59525f82726aSMatthew G. Knepley }
59535f82726aSMatthew G. Knepley 
59545f82726aSMatthew G. Knepley static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
59555f82726aSMatthew G. Knepley {
59565f82726aSMatthew G. Knepley   PetscFunctionBeginHot;
59575f82726aSMatthew G. Knepley   if (tensor) {
59585f82726aSMatthew G. Knepley     *dof = PetscPowInt(k + 1, dim);
59595f82726aSMatthew G. Knepley   } else {
59605f82726aSMatthew G. Knepley     switch (dim) {
59615f82726aSMatthew G. Knepley     case 1:
59625f82726aSMatthew G. Knepley       *dof = k + 1;
59635f82726aSMatthew G. Knepley       break;
59645f82726aSMatthew G. Knepley     case 2:
59655f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2)) / 2;
59665f82726aSMatthew G. Knepley       break;
59675f82726aSMatthew G. Knepley     case 3:
59685f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
59695f82726aSMatthew G. Knepley       break;
59705f82726aSMatthew G. Knepley     default:
59715f82726aSMatthew G. Knepley       *dof = 0;
59725f82726aSMatthew G. Knepley     }
59739e8305c2SJed Brown   }
59743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59759e8305c2SJed Brown }
59769e8305c2SJed Brown 
5977a4355906SMatthew Knepley /*@
5978bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5979bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
598020f4b53cSBarry Smith   section provided (or the section of the `DM`).
5981a4355906SMatthew Knepley 
5982a4355906SMatthew Knepley   Input Parameters:
598320f4b53cSBarry Smith + dm      - The `DM`
598420f4b53cSBarry Smith . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
598520f4b53cSBarry Smith - section - The `PetscSection` to reorder, or `NULL` for the default section
5986a4355906SMatthew Knepley 
5987bc1eb3faSJed Brown   Example:
5988bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5989bc1eb3faSJed Brown .vb
5990bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5991bc1eb3faSJed Brown 
5992bc1eb3faSJed Brown   v4 -- e6 -- v3
5993bc1eb3faSJed Brown   |           |
5994bc1eb3faSJed Brown   e7    c0    e8
5995bc1eb3faSJed Brown   |           |
5996bc1eb3faSJed Brown   v1 -- e5 -- v2
5997bc1eb3faSJed Brown .ve
5998bc1eb3faSJed Brown 
5999bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
6000bc1eb3faSJed Brown   dofs in the order of points, e.g.,
6001bc1eb3faSJed Brown .vb
6002bc1eb3faSJed Brown     c0 -> [0,1,2,3]
6003bc1eb3faSJed Brown     v1 -> [4]
6004bc1eb3faSJed Brown     ...
6005bc1eb3faSJed Brown     e5 -> [8, 9]
6006bc1eb3faSJed Brown .ve
6007bc1eb3faSJed Brown 
6008bc1eb3faSJed Brown   which corresponds to the dofs
6009bc1eb3faSJed Brown .vb
6010bc1eb3faSJed Brown     6   10  11  7
6011bc1eb3faSJed Brown     13  2   3   15
6012bc1eb3faSJed Brown     12  0   1   14
6013bc1eb3faSJed Brown     4   8   9   5
6014bc1eb3faSJed Brown .ve
6015bc1eb3faSJed Brown 
6016bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
6017bc1eb3faSJed Brown .vb
6018bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
6019bc1eb3faSJed Brown .ve
6020bc1eb3faSJed Brown 
6021bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
6022bc1eb3faSJed Brown .vb
6023bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
6024bc1eb3faSJed Brown .ve
6025bc1eb3faSJed Brown 
6026a4355906SMatthew Knepley   Level: developer
6027a4355906SMatthew Knepley 
6028da9ac489SAlbert Cowie   Notes:
6029a1cb98faSBarry Smith   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
6030a1cb98faSBarry Smith   degree of the basis.
6031a1cb98faSBarry Smith 
6032da9ac489SAlbert Cowie   This is required to run with libCEED.
6033da9ac489SAlbert Cowie 
60341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
6035a4355906SMatthew Knepley @*/
6036d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
6037d71ae5a4SJacob Faibussowitsch {
60387391a63aSMatthew G. Knepley   DMLabel   label;
6039bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
60405f82726aSMatthew G. Knepley   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;
60413194fc30SMatthew G. Knepley 
60423194fc30SMatthew G. Knepley   PetscFunctionBegin;
60439566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
60443ba16761SJacob Faibussowitsch   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
6045a433471fSStefano Zampini   if (point < 0) {
6046a433471fSStefano Zampini     PetscInt sStart, sEnd;
6047a433471fSStefano Zampini 
60489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
6049a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
6050a433471fSStefano Zampini   }
60519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
60529566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
60539566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
60549371c9d4SSatish Balay   if (depth == 1) {
60559371c9d4SSatish Balay     eStart = point;
60569371c9d4SSatish Balay   } else if (depth == dim) {
60577391a63aSMatthew G. Knepley     const PetscInt *cone;
60587391a63aSMatthew G. Knepley 
60599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
6060d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
6061d4e6627bSStefano Zampini     else if (dim == 3) {
6062d4e6627bSStefano Zampini       const PetscInt *cone2;
60639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
6064d4e6627bSStefano Zampini       eStart = cone2[0];
606563a3b9bcSJacob 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);
606663a3b9bcSJacob 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);
6067e327e467SRezgar Shakeri 
60689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
6069bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
6070bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
6071bb197d40SJed Brown     PetscInt *perm;
6072bb197d40SJed Brown 
60733194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
60745f82726aSMatthew G. Knepley       PetscInt dof;
60755f82726aSMatthew G. Knepley 
60765f82726aSMatthew G. Knepley       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
60775f82726aSMatthew G. Knepley       PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f);
60785f82726aSMatthew G. Knepley       if (!continuous && d < dim) continue;
60795f82726aSMatthew G. Knepley       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
60805f82726aSMatthew G. Knepley       size += dof * Nc;
60813194fc30SMatthew G. Knepley     }
60829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
60833194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
6084bb197d40SJed Brown       switch (d) {
6085babf31e0SJed Brown       case 1:
60865f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
60875f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
6088babf31e0SJed Brown         /*
6089babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
6090babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
6091babf31e0SJed Brown          */
6092e327e467SRezgar Shakeri         if (continuous) {
6093babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
60949371c9d4SSatish Balay           for (i = 0; i < k - 1; i++)
60959371c9d4SSatish Balay             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
6096babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
6097babf31e0SJed Brown           foffset = offset;
6098e327e467SRezgar Shakeri         } else {
60995f82726aSMatthew G. Knepley           PetscInt dof;
61005f82726aSMatthew G. Knepley 
61015f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
61025f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
61035f82726aSMatthew G. Knepley           foffset = offset;
6104e327e467SRezgar Shakeri         }
6105babf31e0SJed Brown         break;
610689eabcffSMatthew G. Knepley       case 2:
61073194fc30SMatthew 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} */
61085f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
61095f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
61103194fc30SMatthew G. Knepley         /* The SEM order is
61113194fc30SMatthew G. Knepley 
61123194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
611389eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
61143194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
61153194fc30SMatthew G. Knepley          */
6116e327e467SRezgar Shakeri         if (continuous) {
61173194fc30SMatthew G. Knepley           const PetscInt of   = 0;
61183194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
61193194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
61203194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
61213194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
61223194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
61233194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
61243194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
61253194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
61263194fc30SMatthew G. Knepley           PetscInt       o;
61273194fc30SMatthew G. Knepley 
61283194fc30SMatthew G. Knepley           /* bottom */
61293194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
61309371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
61319371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61323194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
61333194fc30SMatthew G. Knepley           /* middle */
61343194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
61353194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
61369371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
61379371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61383194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
61393194fc30SMatthew G. Knepley           }
61403194fc30SMatthew G. Knepley           /* top */
61413194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
61429371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
61439371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61443194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
61453194fc30SMatthew G. Knepley           foffset = offset;
6146e327e467SRezgar Shakeri         } else {
61475f82726aSMatthew G. Knepley           PetscInt dof;
61485f82726aSMatthew G. Knepley 
61495f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
61505f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
61515f82726aSMatthew G. Knepley           foffset = offset;
61523194fc30SMatthew G. Knepley         }
615389eabcffSMatthew G. Knepley         break;
615489eabcffSMatthew G. Knepley       case 3:
615589eabcffSMatthew G. Knepley         /* The original hex closure is
615689eabcffSMatthew G. Knepley 
615789eabcffSMatthew G. Knepley          {c,
615889eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
615989eabcffSMatthew 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,
616089eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
616189eabcffSMatthew G. Knepley          */
61625f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
61635f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
616489eabcffSMatthew G. Knepley         /* The SEM order is
616589eabcffSMatthew G. Knepley          Bottom Slice
616689eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
616789eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
616889eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
616989eabcffSMatthew G. Knepley 
617089eabcffSMatthew G. Knepley          Middle Slice (j)
617189eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
617289eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
617389eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
617489eabcffSMatthew G. Knepley 
617589eabcffSMatthew G. Knepley          Top Slice
617689eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
617789eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
617889eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
617989eabcffSMatthew G. Knepley          */
6180e327e467SRezgar Shakeri         if (continuous) {
618189eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
618289eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
618389eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
618489eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
618589eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
618689eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
618789eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
618889eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
618989eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
619089eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
619189eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
619289eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
619389eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
619489eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
619589eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
619689eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
619789eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
619889eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
619989eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
620089eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
620189eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
620289eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
620389eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
620489eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
620589eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
620689eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
620789eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
620889eabcffSMatthew G. Knepley           PetscInt       o, n;
620989eabcffSMatthew G. Knepley 
621089eabcffSMatthew G. Knepley           /* Bottom Slice */
621189eabcffSMatthew G. Knepley           /*   bottom */
621289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
62139371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
62149371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
621589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
621689eabcffSMatthew G. Knepley           /*   middle */
621789eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
621889eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
62199371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
62209371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
62219371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
62229371c9d4SSatish Balay             }
622389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
62243194fc30SMatthew G. Knepley           }
622589eabcffSMatthew G. Knepley           /*   top */
622689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
62279371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
62289371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
622989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
623089eabcffSMatthew G. Knepley 
623189eabcffSMatthew G. Knepley           /* Middle Slice */
623289eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
623389eabcffSMatthew G. Knepley             /*   bottom */
623489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
62359371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
62369371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
623789eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
623889eabcffSMatthew G. Knepley             /*   middle */
623989eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
624089eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
62419371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
62429371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
624389eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
624489eabcffSMatthew G. Knepley             }
624589eabcffSMatthew G. Knepley             /*   top */
624689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
62479371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
62489371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
624989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
625089eabcffSMatthew G. Knepley           }
625189eabcffSMatthew G. Knepley 
625289eabcffSMatthew G. Knepley           /* Top Slice */
625389eabcffSMatthew G. Knepley           /*   bottom */
625489eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
62559371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
62569371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
625789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
625889eabcffSMatthew G. Knepley           /*   middle */
625989eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
626089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
62619371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
62629371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
626389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
626489eabcffSMatthew G. Knepley           }
626589eabcffSMatthew G. Knepley           /*   top */
626689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
62679371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
62689371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
626989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
627089eabcffSMatthew G. Knepley 
627189eabcffSMatthew G. Knepley           foffset = offset;
6272e327e467SRezgar Shakeri         } else {
62735f82726aSMatthew G. Knepley           PetscInt dof;
62745f82726aSMatthew G. Knepley 
62755f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
62765f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
62775f82726aSMatthew G. Knepley           foffset = offset;
627889eabcffSMatthew G. Knepley         }
627989eabcffSMatthew G. Knepley         break;
6280d71ae5a4SJacob Faibussowitsch       default:
6281d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
628289eabcffSMatthew G. Knepley       }
628389eabcffSMatthew G. Knepley     }
628463a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
62853194fc30SMatthew G. Knepley     /* Check permutation */
62863194fc30SMatthew G. Knepley     {
62873194fc30SMatthew G. Knepley       PetscInt *check;
62883194fc30SMatthew G. Knepley 
62899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
62901dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
62911dca8a05SBarry Smith         check[i] = -1;
62921dca8a05SBarry 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]);
62931dca8a05SBarry Smith       }
62943194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
62951dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
62969566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
62973194fc30SMatthew G. Knepley     }
62989566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6299a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6300a05c9aa3SJed Brown       PetscInt *loc_perm;
63019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6302a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
6303a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
6304a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
6305a05c9aa3SJed Brown       }
63069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6307a05c9aa3SJed Brown     }
6308bb197d40SJed Brown   }
63093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63103194fc30SMatthew G. Knepley }
63113194fc30SMatthew G. Knepley 
6312d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6313d71ae5a4SJacob Faibussowitsch {
6314e071409bSToby Isaac   PetscDS  prob;
6315e071409bSToby Isaac   PetscInt depth, Nf, h;
6316e071409bSToby Isaac   DMLabel  label;
6317e071409bSToby Isaac 
6318e071409bSToby Isaac   PetscFunctionBeginHot;
63199566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
6320e071409bSToby Isaac   Nf      = prob->Nf;
6321e071409bSToby Isaac   label   = dm->depthLabel;
6322e071409bSToby Isaac   *dspace = NULL;
6323e071409bSToby Isaac   if (field < Nf) {
6324e071409bSToby Isaac     PetscObject disc = prob->disc[field];
6325e071409bSToby Isaac 
6326e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
6327e071409bSToby Isaac       PetscDualSpace dsp;
6328e071409bSToby Isaac 
63299566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
63309566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
63319566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
6332e071409bSToby Isaac       h = depth - 1 - h;
6333e071409bSToby Isaac       if (h) {
63349566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6335e071409bSToby Isaac       } else {
6336e071409bSToby Isaac         *dspace = dsp;
6337e071409bSToby Isaac       }
6338e071409bSToby Isaac     }
6339e071409bSToby Isaac   }
63403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6341e071409bSToby Isaac }
6342e071409bSToby Isaac 
6343d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6344d71ae5a4SJacob Faibussowitsch {
634528351e22SJed Brown   PetscScalar       *array;
634628351e22SJed Brown   const PetscScalar *vArray;
6347d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
63481a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
6349552f7358SJed Brown 
63501b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
63519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
63529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
63539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
63549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
63553f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
63569df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
63579df71ca4SMatthew G. Knepley       PetscInt dof;
6358d9917b9dSMatthew G. Knepley 
63599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
63609df71ca4SMatthew G. Knepley       size += dof;
63619df71ca4SMatthew G. Knepley     }
63629df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
63639df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
63642a3aaacfSMatthew G. Knepley       PetscInt       dof;
63655a1bb5cfSMatthew G. Knepley 
63665a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
63679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
63685a1bb5cfSMatthew G. Knepley       size += dof;
63695a1bb5cfSMatthew G. Knepley     }
63703f7cbbe7SMatthew G. Knepley     if (!values) {
63713f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
63723ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
63733f7cbbe7SMatthew G. Knepley     }
63749566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6375982e9ed1SMatthew G. Knepley   } else {
6376982e9ed1SMatthew G. Knepley     array = *values;
6377982e9ed1SMatthew G. Knepley   }
63789df71ca4SMatthew G. Knepley   size = 0;
637928351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
63809df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
63819df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
638228351e22SJed Brown     const PetscScalar *varr;
6383d9917b9dSMatthew G. Knepley 
63849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
63859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
63868e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
6387ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
63889df71ca4SMatthew G. Knepley     size += dof;
63899df71ca4SMatthew G. Knepley   }
63909df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
63919df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
63929df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
63935a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
639428351e22SJed Brown     const PetscScalar *varr;
63955a1bb5cfSMatthew G. Knepley 
639652ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
63979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
63989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
63998e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
64005a1bb5cfSMatthew G. Knepley     if (o >= 0) {
6401ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
64025a1bb5cfSMatthew G. Knepley     } else {
6403ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
64045a1bb5cfSMatthew G. Knepley     }
64059df71ca4SMatthew G. Knepley     size += dof;
64065a1bb5cfSMatthew G. Knepley   }
640728351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
64089df71ca4SMatthew G. Knepley   if (!*values) {
64095a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
64105a1bb5cfSMatthew G. Knepley     *values = array;
64119df71ca4SMatthew G. Knepley   } else {
641263a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
64138c312ff3SMatthew G. Knepley     *csize = size;
64149df71ca4SMatthew G. Knepley   }
64153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64165a1bb5cfSMatthew G. Knepley }
6417d9917b9dSMatthew G. Knepley 
641827f02ce8SMatthew G. Knepley /* Compress out points not in the section */
6419d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6420d71ae5a4SJacob Faibussowitsch {
642127f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
642227f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
642327f02ce8SMatthew G. Knepley 
64249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
642527f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
642627f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
642727f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
642827f02ce8SMatthew G. Knepley       points[q * 2]     = r;
642927f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
643027f02ce8SMatthew G. Knepley       ++q;
643127f02ce8SMatthew G. Knepley     }
643227f02ce8SMatthew G. Knepley   }
643327f02ce8SMatthew G. Knepley   *numPoints = q;
64343ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
643527f02ce8SMatthew G. Knepley }
643627f02ce8SMatthew G. Knepley 
643797529cf3SJed Brown /* Compressed closure does not apply closure permutation */
643807218a29SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6439d71ae5a4SJacob Faibussowitsch {
644027f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
6441923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
6442923c78e0SToby Isaac 
6443923c78e0SToby Isaac   PetscFunctionBeginHot;
64449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
644507218a29SMatthew G. Knepley   if (!ornt && *clPoints) {
6446923c78e0SToby Isaac     PetscInt dof, off;
6447923c78e0SToby Isaac 
64489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
64499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
64509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
6451923c78e0SToby Isaac     np  = dof / 2;
64528e3a54c0SPierre Jolivet     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
645327f02ce8SMatthew G. Knepley   } else {
645407218a29SMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
64559566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
6456923c78e0SToby Isaac   }
6457923c78e0SToby Isaac   *numPoints = np;
6458923c78e0SToby Isaac   *points    = pts;
6459923c78e0SToby Isaac   *clp       = cla;
64603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6461923c78e0SToby Isaac }
6462923c78e0SToby Isaac 
6463d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6464d71ae5a4SJacob Faibussowitsch {
6465923c78e0SToby Isaac   PetscFunctionBeginHot;
6466923c78e0SToby Isaac   if (!*clPoints) {
64679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6468923c78e0SToby Isaac   } else {
64699566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
6470923c78e0SToby Isaac   }
6471923c78e0SToby Isaac   *numPoints = 0;
6472923c78e0SToby Isaac   *points    = NULL;
6473923c78e0SToby Isaac   *clSec     = NULL;
6474923c78e0SToby Isaac   *clPoints  = NULL;
6475923c78e0SToby Isaac   *clp       = NULL;
64763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6477923c78e0SToby Isaac }
6478923c78e0SToby Isaac 
6479d71ae5a4SJacob 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[])
6480d71ae5a4SJacob Faibussowitsch {
64811a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
648297e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
648397e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
64841a271a75SMatthew G. Knepley 
64851a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6486fe02ba77SJed Brown   *size = 0;
64879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
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;
64921a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
64931a271a75SMatthew G. Knepley     const PetscScalar *varr;
64941a271a75SMatthew G. Knepley 
64959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
64969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
64978e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
649897e99dd9SToby Isaac     if (clperm) {
649997e99dd9SToby Isaac       if (perm) {
650097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
65011a271a75SMatthew G. Knepley       } else {
650297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
650397e99dd9SToby Isaac       }
650497e99dd9SToby Isaac       if (flip) {
650597e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
650697e99dd9SToby Isaac       }
650797e99dd9SToby Isaac     } else {
650897e99dd9SToby Isaac       if (perm) {
650997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
651097e99dd9SToby Isaac       } else {
651197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
651297e99dd9SToby Isaac       }
651397e99dd9SToby Isaac       if (flip) {
651497e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
65151a271a75SMatthew G. Knepley       }
65161a271a75SMatthew G. Knepley     }
651797e99dd9SToby Isaac     offset += dof;
651897e99dd9SToby Isaac   }
65199566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
65201a271a75SMatthew G. Knepley   *size = offset;
65213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
65221a271a75SMatthew G. Knepley }
65231a271a75SMatthew G. Knepley 
6524d71ae5a4SJacob 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[])
6525d71ae5a4SJacob Faibussowitsch {
65261a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
65271a271a75SMatthew G. Knepley 
65281a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6529fe02ba77SJed Brown   *size = 0;
65301a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
653197e99dd9SToby Isaac     PetscInt            p;
653297e99dd9SToby Isaac     const PetscInt    **perms = NULL;
653397e99dd9SToby Isaac     const PetscScalar **flips = NULL;
65341a271a75SMatthew G. Knepley 
65359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
653697e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
653797e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
653897e99dd9SToby Isaac       PetscInt           fdof, foff, b;
65391a271a75SMatthew G. Knepley       const PetscScalar *varr;
654097e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
654197e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
65421a271a75SMatthew G. Knepley 
65439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
65449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
65451a271a75SMatthew G. Knepley       varr = &vArray[foff];
654697e99dd9SToby Isaac       if (clperm) {
65479371c9d4SSatish Balay         if (perm) {
6548ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
65491a271a75SMatthew G. Knepley         } else {
6550ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
65519371c9d4SSatish Balay         }
65529371c9d4SSatish Balay         if (flip) {
6553ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
65549371c9d4SSatish Balay         }
65559371c9d4SSatish Balay       } else {
65569371c9d4SSatish Balay         if (perm) {
6557ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
65589371c9d4SSatish Balay         } else {
6559ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
65609371c9d4SSatish Balay         }
65619371c9d4SSatish Balay         if (flip) {
6562ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
65639371c9d4SSatish Balay         }
65641a271a75SMatthew G. Knepley       }
656597e99dd9SToby Isaac       offset += fdof;
65661a271a75SMatthew G. Knepley     }
65679566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
65681a271a75SMatthew G. Knepley   }
65691a271a75SMatthew G. Knepley   *size = offset;
65703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
65711a271a75SMatthew G. Knepley }
65721a271a75SMatthew G. Knepley 
657348162695SZach Atkins /*@C
657448162695SZach Atkins   DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation.
657548162695SZach Atkins 
657648162695SZach Atkins   Not collective
657748162695SZach Atkins 
657848162695SZach Atkins   Input Parameters:
657948162695SZach Atkins + dm        - The `DM`
658048162695SZach Atkins . section   - The section describing the layout in `v`, or `NULL` to use the default section
658148162695SZach Atkins . useClPerm - Flag for whether the provided closure permutation should be applied to the values
658248162695SZach Atkins . v         - The local vector
658348162695SZach Atkins . point     - The point in the `DM`
658448162695SZach Atkins - ornt      - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0.
658548162695SZach Atkins 
658648162695SZach Atkins   Input/Output Parameters:
658748162695SZach Atkins + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
658848162695SZach Atkins - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
658948162695SZach Atkins            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
659048162695SZach Atkins 
659148162695SZach Atkins   Level: advanced
659248162695SZach Atkins 
659348162695SZach Atkins   Notes:
659448162695SZach Atkins   `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
659548162695SZach Atkins   calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat`
659648162695SZach Atkins   assembly function, and a user may already have allocated storage for this operation.
659748162695SZach Atkins 
659848162695SZach Atkins   Fortran Notes:
659948162695SZach Atkins   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
660048162695SZach Atkins   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
660148162695SZach Atkins 
660248162695SZach Atkins   `values` must be declared with
660348162695SZach Atkins .vb
660448162695SZach Atkins   PetscScalar,dimension(:),pointer   :: values
660548162695SZach Atkins .ve
660648162695SZach Atkins   and it will be allocated internally by PETSc to hold the values returned
660748162695SZach Atkins 
660848162695SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`
660948162695SZach Atkins @*/
661048162695SZach Atkins PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
661107218a29SMatthew G. Knepley {
661207218a29SMatthew G. Knepley   PetscSection    clSection;
661307218a29SMatthew G. Knepley   IS              clPoints;
661407218a29SMatthew G. Knepley   PetscInt       *points = NULL;
6615e8e188d2SZach Atkins   const PetscInt *clp, *perm = NULL;
661607218a29SMatthew G. Knepley   PetscInt        depth, numFields, numPoints, asize;
661707218a29SMatthew G. Knepley 
661807218a29SMatthew G. Knepley   PetscFunctionBeginHot;
661907218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
662007218a29SMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
662107218a29SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6622e8e188d2SZach Atkins   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
662307218a29SMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
662407218a29SMatthew G. Knepley   PetscCall(PetscSectionGetNumFields(section, &numFields));
662507218a29SMatthew G. Knepley   if (depth == 1 && numFields < 2) {
662607218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
662707218a29SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
662807218a29SMatthew G. Knepley   }
662907218a29SMatthew G. Knepley   /* Get points */
663007218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
663107218a29SMatthew G. Knepley   /* Get sizes */
663207218a29SMatthew G. Knepley   asize = 0;
663307218a29SMatthew G. Knepley   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
663407218a29SMatthew G. Knepley     PetscInt dof;
663507218a29SMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, points[p], &dof));
663607218a29SMatthew G. Knepley     asize += dof;
663707218a29SMatthew G. Knepley   }
663807218a29SMatthew G. Knepley   if (values) {
663907218a29SMatthew G. Knepley     const PetscScalar *vArray;
664007218a29SMatthew G. Knepley     PetscInt           size;
664107218a29SMatthew G. Knepley 
664207218a29SMatthew G. Knepley     if (*values) {
664307218a29SMatthew G. Knepley       PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize);
664407218a29SMatthew G. Knepley     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6645e8e188d2SZach Atkins     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
664607218a29SMatthew G. Knepley     PetscCall(VecGetArrayRead(v, &vArray));
664707218a29SMatthew G. Knepley     /* Get values */
664807218a29SMatthew G. Knepley     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
664907218a29SMatthew G. Knepley     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
665007218a29SMatthew G. Knepley     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
665107218a29SMatthew G. Knepley     /* Cleanup array */
665207218a29SMatthew G. Knepley     PetscCall(VecRestoreArrayRead(v, &vArray));
665307218a29SMatthew G. Knepley   }
665407218a29SMatthew G. Knepley   if (csize) *csize = asize;
665507218a29SMatthew G. Knepley   /* Cleanup points */
665607218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
665707218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
665807218a29SMatthew G. Knepley }
665907218a29SMatthew G. Knepley 
6660552f7358SJed Brown /*@C
6661552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6662552f7358SJed Brown 
6663552f7358SJed Brown   Not collective
6664552f7358SJed Brown 
6665552f7358SJed Brown   Input Parameters:
6666a1cb98faSBarry Smith + dm      - The `DM`
666720f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6668552f7358SJed Brown . v       - The local vector
6669a1cb98faSBarry Smith - point   - The point in the `DM`
6670552f7358SJed Brown 
66716b867d5aSJose E. Roman   Input/Output Parameters:
667220f4b53cSBarry Smith + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
66732c9a7b26SBarry Smith - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
66742c9a7b26SBarry Smith            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
667522c1ee49SMatthew G. Knepley 
6676552f7358SJed Brown   Level: intermediate
6677552f7358SJed Brown 
6678a1cb98faSBarry Smith   Notes:
667944a422c4SJames Wright   This is used for getting the all values in a `Vec` in the closure of a mesh point.
668044a422c4SJames Wright   To get only the values in the closure of a mesh point at a specific depth (for example, at mesh vertices), use `DMPlexVecGetClosureAtDepth()`.
668144a422c4SJames Wright 
668220f4b53cSBarry Smith   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6683a1cb98faSBarry Smith   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6684a1cb98faSBarry Smith   assembly function, and a user may already have allocated storage for this operation.
6685a1cb98faSBarry Smith 
6686a1cb98faSBarry Smith   A typical use could be
6687a1cb98faSBarry Smith .vb
6688a1cb98faSBarry Smith    values = NULL;
6689a1cb98faSBarry Smith    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6690a1cb98faSBarry Smith    for (cl = 0; cl < clSize; ++cl) {
6691a1cb98faSBarry Smith      <Compute on closure>
6692a1cb98faSBarry Smith    }
6693a1cb98faSBarry Smith    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6694a1cb98faSBarry Smith .ve
6695a1cb98faSBarry Smith   or
6696a1cb98faSBarry Smith .vb
6697a1cb98faSBarry Smith    PetscMalloc1(clMaxSize, &values);
6698a1cb98faSBarry Smith    for (p = pStart; p < pEnd; ++p) {
6699a1cb98faSBarry Smith      clSize = clMaxSize;
6700a1cb98faSBarry Smith      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6701a1cb98faSBarry Smith      for (cl = 0; cl < clSize; ++cl) {
6702a1cb98faSBarry Smith        <Compute on closure>
6703a1cb98faSBarry Smith      }
6704a1cb98faSBarry Smith    }
6705a1cb98faSBarry Smith    PetscFree(values);
6706a1cb98faSBarry Smith .ve
6707a1cb98faSBarry Smith 
670860225df5SJacob Faibussowitsch   Fortran Notes:
6709ce78bad3SBarry Smith   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
6710ce78bad3SBarry Smith   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6711a1cb98faSBarry Smith 
6712f13dfd9eSBarry Smith   `values` must be declared with
6713f13dfd9eSBarry Smith .vb
6714f13dfd9eSBarry Smith   PetscScalar,dimension(:),pointer   :: values
6715f13dfd9eSBarry Smith .ve
6716f13dfd9eSBarry Smith   and it will be allocated internally by PETSc to hold the values returned
6717f13dfd9eSBarry Smith 
671844a422c4SJames Wright .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosureAtDepth()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6719552f7358SJed Brown @*/
6720d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6721d71ae5a4SJacob Faibussowitsch {
6722d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
672348162695SZach Atkins   PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values));
67243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6725552f7358SJed Brown }
6726552f7358SJed Brown 
672744a422c4SJames Wright /*@C
672844a422c4SJames Wright   DMPlexVecGetClosureAtDepth - Get an array of the values on the closure of 'point' that are at a specific depth
672944a422c4SJames Wright 
673044a422c4SJames Wright   Not collective
673144a422c4SJames Wright 
673244a422c4SJames Wright   Input Parameters:
673344a422c4SJames Wright + dm      - The `DM`
673444a422c4SJames Wright . section - The section describing the layout in `v`, or `NULL` to use the default section
673544a422c4SJames Wright . v       - The local vector
673644a422c4SJames Wright . depth   - The depth of mesh points that should be returned
673744a422c4SJames Wright - point   - The point in the `DM`
673844a422c4SJames Wright 
673944a422c4SJames Wright   Input/Output Parameters:
674044a422c4SJames Wright + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
674144a422c4SJames Wright - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
674244a422c4SJames Wright            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
674344a422c4SJames Wright 
674444a422c4SJames Wright   Level: intermediate
674544a422c4SJames Wright 
674644a422c4SJames Wright   Notes:
674744a422c4SJames Wright   This is used for getting the values in a `Vec` associated with specific mesh points.
674844a422c4SJames Wright   For example, to get only the values at mesh vertices, pass `depth=0`. To get all the values in the closure of a mesh point, use `DMPlexVecGetClosure()`.
674944a422c4SJames Wright 
675044a422c4SJames Wright   `DMPlexVecGetClosureAtDepth()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
675144a422c4SJames Wright   calling function. This is because `DMPlexVecGetClosureAtDepth()` is typically called in the inner loop of a `Vec` or `Mat`
675244a422c4SJames Wright   assembly function, and a user may already have allocated storage for this operation.
675344a422c4SJames Wright 
675444a422c4SJames Wright   A typical use could be
675544a422c4SJames Wright .vb
675644a422c4SJames Wright    values = NULL;
675744a422c4SJames Wright    PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values));
675844a422c4SJames Wright    for (cl = 0; cl < clSize; ++cl) {
675944a422c4SJames Wright      <Compute on closure>
676044a422c4SJames Wright    }
676144a422c4SJames Wright    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
676244a422c4SJames Wright .ve
676344a422c4SJames Wright   or
676444a422c4SJames Wright .vb
676544a422c4SJames Wright    PetscMalloc1(clMaxSize, &values);
676644a422c4SJames Wright    for (p = pStart; p < pEnd; ++p) {
676744a422c4SJames Wright      clSize = clMaxSize;
676844a422c4SJames Wright      PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values));
676944a422c4SJames Wright      for (cl = 0; cl < clSize; ++cl) {
677044a422c4SJames Wright        <Compute on closure>
677144a422c4SJames Wright      }
677244a422c4SJames Wright    }
677344a422c4SJames Wright    PetscFree(values);
677444a422c4SJames Wright .ve
677544a422c4SJames Wright 
677644a422c4SJames Wright   Fortran Notes:
677744a422c4SJames Wright   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
677844a422c4SJames Wright   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
677944a422c4SJames Wright 
678044a422c4SJames Wright   `values` must be declared with
678144a422c4SJames Wright .vb
678244a422c4SJames Wright   PetscScalar,dimension(:),pointer   :: values
678344a422c4SJames Wright .ve
678444a422c4SJames Wright   and it will be allocated internally by PETSc to hold the values returned
678544a422c4SJames Wright 
678644a422c4SJames Wright .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
678744a422c4SJames Wright @*/
678844a422c4SJames Wright PetscErrorCode DMPlexVecGetClosureAtDepth(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6789d71ae5a4SJacob Faibussowitsch {
6790e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6791e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6792e5c487bfSMatthew G. Knepley   IS                 clPoints;
6793e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6794e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6795e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6796c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6797c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6798e5c487bfSMatthew G. Knepley 
6799e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6800e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
68019566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6802e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6803e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
68049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
68059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
68069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6807e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
68089566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
68093ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6810e5c487bfSMatthew G. Knepley   }
6811e5c487bfSMatthew G. Knepley   /* Get points */
681207218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6813c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6814c459fbc1SJed Brown     PetscInt dof;
68159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6816c459fbc1SJed Brown     clsize += dof;
6817c459fbc1SJed Brown   }
68189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6819e5c487bfSMatthew G. Knepley   /* Filter points */
6820e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6821e5c487bfSMatthew G. Knepley     PetscInt dep;
6822e5c487bfSMatthew G. Knepley 
68239566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6824e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6825e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6826e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6827e5c487bfSMatthew G. Knepley     ++Np;
6828e5c487bfSMatthew G. Knepley   }
6829e5c487bfSMatthew G. Knepley   /* Get array */
6830e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6831e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6832e5c487bfSMatthew G. Knepley 
6833e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
68349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6835e5c487bfSMatthew G. Knepley       asize += dof;
6836e5c487bfSMatthew G. Knepley     }
6837e5c487bfSMatthew G. Knepley     if (!values) {
68389566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6839e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
68403ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
6841e5c487bfSMatthew G. Knepley     }
68429566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6843e5c487bfSMatthew G. Knepley   } else {
6844e5c487bfSMatthew G. Knepley     array = *values;
6845e5c487bfSMatthew G. Knepley   }
68469566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6847e5c487bfSMatthew G. Knepley   /* Get values */
68489566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
68499566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6850e5c487bfSMatthew G. Knepley   /* Cleanup points */
68519566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6852e5c487bfSMatthew G. Knepley   /* Cleanup array */
68539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6854e5c487bfSMatthew G. Knepley   if (!*values) {
6855e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6856e5c487bfSMatthew G. Knepley     *values = array;
6857e5c487bfSMatthew G. Knepley   } else {
685863a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6859e5c487bfSMatthew G. Knepley     *csize = size;
6860e5c487bfSMatthew G. Knepley   }
68613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6862e5c487bfSMatthew G. Knepley }
6863e5c487bfSMatthew G. Knepley 
6864552f7358SJed Brown /*@C
6865f13dfd9eSBarry Smith   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()`
6866552f7358SJed Brown 
6867552f7358SJed Brown   Not collective
6868552f7358SJed Brown 
6869552f7358SJed Brown   Input Parameters:
6870a1cb98faSBarry Smith + dm      - The `DM`
687120f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6872552f7358SJed Brown . v       - The local vector
6873a1cb98faSBarry Smith . point   - The point in the `DM`
687420f4b53cSBarry Smith . csize   - The number of values in the closure, or `NULL`
6875f13dfd9eSBarry Smith - values  - The array of values
6876552f7358SJed Brown 
6877552f7358SJed Brown   Level: intermediate
6878552f7358SJed Brown 
6879a1cb98faSBarry Smith   Note:
688020f4b53cSBarry Smith   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6881a1cb98faSBarry Smith 
6882f13dfd9eSBarry Smith   Fortran Note:
6883ce78bad3SBarry Smith   The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed.
6884ce78bad3SBarry Smith   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6885a1cb98faSBarry Smith 
68861cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6887552f7358SJed Brown @*/
6888d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6889d71ae5a4SJacob Faibussowitsch {
6890552f7358SJed Brown   PetscInt size = 0;
6891552f7358SJed Brown 
6892552f7358SJed Brown   PetscFunctionBegin;
6893552f7358SJed Brown   /* Should work without recalculating size */
68949566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6895c9fdaa05SMatthew G. Knepley   *values = NULL;
68963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6897552f7358SJed Brown }
6898552f7358SJed Brown 
6899d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6900d71ae5a4SJacob Faibussowitsch {
69019371c9d4SSatish Balay   *x += y;
69029371c9d4SSatish Balay }
6903d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6904d71ae5a4SJacob Faibussowitsch {
69059371c9d4SSatish Balay   *x = y;
69069371c9d4SSatish Balay }
6907552f7358SJed Brown 
6908d71ae5a4SJacob 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[])
6909d71ae5a4SJacob Faibussowitsch {
6910552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6911552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6912552f7358SJed Brown   PetscScalar    *a;
6913552f7358SJed Brown   PetscInt        off, cind = 0, k;
6914552f7358SJed Brown 
6915552f7358SJed Brown   PetscFunctionBegin;
69169566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
69179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6918552f7358SJed Brown   a = &array[off];
6919552f7358SJed Brown   if (!cdof || setBC) {
692097e99dd9SToby Isaac     if (clperm) {
69219371c9d4SSatish Balay       if (perm) {
6922ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6923552f7358SJed Brown       } else {
6924ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
69259371c9d4SSatish Balay       }
69269371c9d4SSatish Balay     } else {
69279371c9d4SSatish Balay       if (perm) {
6928ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
69299371c9d4SSatish Balay       } else {
6930ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
69319371c9d4SSatish Balay       }
6932552f7358SJed Brown     }
6933552f7358SJed Brown   } else {
69349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
693597e99dd9SToby Isaac     if (clperm) {
69369371c9d4SSatish Balay       if (perm) {
69379371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
69389371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69399371c9d4SSatish Balay             ++cind;
69409371c9d4SSatish Balay             continue;
69419371c9d4SSatish Balay           }
694297e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6943552f7358SJed Brown         }
6944552f7358SJed Brown       } else {
6945552f7358SJed Brown         for (k = 0; k < dof; ++k) {
69469371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69479371c9d4SSatish Balay             ++cind;
69489371c9d4SSatish Balay             continue;
69499371c9d4SSatish Balay           }
695097e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
695197e99dd9SToby Isaac         }
695297e99dd9SToby Isaac       }
695397e99dd9SToby Isaac     } else {
695497e99dd9SToby Isaac       if (perm) {
695597e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
69569371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69579371c9d4SSatish Balay             ++cind;
69589371c9d4SSatish Balay             continue;
69599371c9d4SSatish Balay           }
696097e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
696197e99dd9SToby Isaac         }
696297e99dd9SToby Isaac       } else {
696397e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
69649371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69659371c9d4SSatish Balay             ++cind;
69669371c9d4SSatish Balay             continue;
69679371c9d4SSatish Balay           }
696897e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
696997e99dd9SToby Isaac         }
6970552f7358SJed Brown       }
6971552f7358SJed Brown     }
6972552f7358SJed Brown   }
69733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6974552f7358SJed Brown }
6975552f7358SJed Brown 
6976d71ae5a4SJacob 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[])
6977d71ae5a4SJacob Faibussowitsch {
6978a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6979a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6980a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6981a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6982a5e93ea8SMatthew G. Knepley 
6983a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
69849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
69859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6986a5e93ea8SMatthew G. Knepley   a = &array[off];
6987a5e93ea8SMatthew G. Knepley   if (cdof) {
69889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
698997e99dd9SToby Isaac     if (clperm) {
699097e99dd9SToby Isaac       if (perm) {
6991a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6992a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
699397e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
699497e99dd9SToby Isaac             cind++;
6995a5e93ea8SMatthew G. Knepley           }
6996a5e93ea8SMatthew G. Knepley         }
6997a5e93ea8SMatthew G. Knepley       } else {
6998a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6999a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
700097e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
700197e99dd9SToby Isaac             cind++;
700297e99dd9SToby Isaac           }
700397e99dd9SToby Isaac         }
700497e99dd9SToby Isaac       }
700597e99dd9SToby Isaac     } else {
700697e99dd9SToby Isaac       if (perm) {
700797e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
700897e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
700997e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
701097e99dd9SToby Isaac             cind++;
701197e99dd9SToby Isaac           }
701297e99dd9SToby Isaac         }
701397e99dd9SToby Isaac       } else {
701497e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
701597e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
701697e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
701797e99dd9SToby Isaac             cind++;
701897e99dd9SToby Isaac           }
7019a5e93ea8SMatthew G. Knepley         }
7020a5e93ea8SMatthew G. Knepley       }
7021a5e93ea8SMatthew G. Knepley     }
7022a5e93ea8SMatthew G. Knepley   }
70233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7024a5e93ea8SMatthew G. Knepley }
7025a5e93ea8SMatthew G. Knepley 
7026d71ae5a4SJacob 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[])
7027d71ae5a4SJacob Faibussowitsch {
7028552f7358SJed Brown   PetscScalar    *a;
70291a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
70301a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
703197e99dd9SToby Isaac   PetscInt        cind = 0, b;
7032552f7358SJed Brown 
7033552f7358SJed Brown   PetscFunctionBegin;
70349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
70359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
70369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
70371a271a75SMatthew G. Knepley   a = &array[foff];
7038552f7358SJed Brown   if (!fcdof || setBC) {
703997e99dd9SToby Isaac     if (clperm) {
70409371c9d4SSatish Balay       if (perm) {
7041ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7042552f7358SJed Brown       } else {
7043ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
70449371c9d4SSatish Balay       }
70459371c9d4SSatish Balay     } else {
70469371c9d4SSatish Balay       if (perm) {
7047ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
70489371c9d4SSatish Balay       } else {
7049ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
70509371c9d4SSatish Balay       }
7051552f7358SJed Brown     }
7052552f7358SJed Brown   } else {
70539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
705497e99dd9SToby Isaac     if (clperm) {
705597e99dd9SToby Isaac       if (perm) {
705697e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70579371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70589371c9d4SSatish Balay             ++cind;
70599371c9d4SSatish Balay             continue;
70609371c9d4SSatish Balay           }
706197e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7062552f7358SJed Brown         }
7063552f7358SJed Brown       } else {
706497e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70659371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70669371c9d4SSatish Balay             ++cind;
70679371c9d4SSatish Balay             continue;
70689371c9d4SSatish Balay           }
706997e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
707097e99dd9SToby Isaac         }
707197e99dd9SToby Isaac       }
707297e99dd9SToby Isaac     } else {
707397e99dd9SToby Isaac       if (perm) {
707497e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70759371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70769371c9d4SSatish Balay             ++cind;
70779371c9d4SSatish Balay             continue;
70789371c9d4SSatish Balay           }
707997e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
708097e99dd9SToby Isaac         }
708197e99dd9SToby Isaac       } else {
708297e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70839371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70849371c9d4SSatish Balay             ++cind;
70859371c9d4SSatish Balay             continue;
70869371c9d4SSatish Balay           }
708797e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7088552f7358SJed Brown         }
7089552f7358SJed Brown       }
7090552f7358SJed Brown     }
7091552f7358SJed Brown   }
70921a271a75SMatthew G. Knepley   *offset += fdof;
70933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7094552f7358SJed Brown }
7095552f7358SJed Brown 
7096d71ae5a4SJacob 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[])
7097d71ae5a4SJacob Faibussowitsch {
7098a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
70991a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
71001a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
71015da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
7102ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
7103a5e93ea8SMatthew G. Knepley 
7104a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
71059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
71069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
71079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
71089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
71091a271a75SMatthew G. Knepley   a = &array[foff];
7110a5e93ea8SMatthew G. Knepley   if (fcdof) {
7111ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
71129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
711397e99dd9SToby Isaac     if (clperm) {
711497e99dd9SToby Isaac       if (perm) {
7115ba322698SMatthew G. Knepley         if (comps) {
7116ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7117ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71189371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71199371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71209371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71219371c9d4SSatish Balay             }
71229371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71239371c9d4SSatish Balay               ++cind;
71249371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71259371c9d4SSatish Balay             }
7126ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7127ba322698SMatthew G. Knepley           }
7128ba322698SMatthew G. Knepley         } else {
712997e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
713097e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
713197e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7132a5e93ea8SMatthew G. Knepley               ++cind;
7133a5e93ea8SMatthew G. Knepley             }
7134a5e93ea8SMatthew G. Knepley           }
7135ba322698SMatthew G. Knepley         }
7136ba322698SMatthew G. Knepley       } else {
7137ba322698SMatthew G. Knepley         if (comps) {
7138ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7139ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71409371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71419371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71429371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71439371c9d4SSatish Balay             }
71449371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71459371c9d4SSatish Balay               ++cind;
71469371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71479371c9d4SSatish Balay             }
7148ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
7149ba322698SMatthew G. Knepley           }
7150a5e93ea8SMatthew G. Knepley         } else {
715197e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
715297e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
715397e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
715497e99dd9SToby Isaac               ++cind;
715597e99dd9SToby Isaac             }
715697e99dd9SToby Isaac           }
715797e99dd9SToby Isaac         }
7158ba322698SMatthew G. Knepley       }
715997e99dd9SToby Isaac     } else {
716097e99dd9SToby Isaac       if (perm) {
7161ba322698SMatthew G. Knepley         if (comps) {
7162ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7163ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71649371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71659371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71669371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71679371c9d4SSatish Balay             }
71689371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71699371c9d4SSatish Balay               ++cind;
71709371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71719371c9d4SSatish Balay             }
7172ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
7173ba322698SMatthew G. Knepley           }
7174ba322698SMatthew G. Knepley         } else {
717597e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
717697e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
717797e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
717897e99dd9SToby Isaac               ++cind;
717997e99dd9SToby Isaac             }
718097e99dd9SToby Isaac           }
7181ba322698SMatthew G. Knepley         }
7182ba322698SMatthew G. Knepley       } else {
7183ba322698SMatthew G. Knepley         if (comps) {
7184ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7185ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71869371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71879371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71889371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71899371c9d4SSatish Balay             }
71909371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71919371c9d4SSatish Balay               ++cind;
71929371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71939371c9d4SSatish Balay             }
7194ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7195ba322698SMatthew G. Knepley           }
719697e99dd9SToby Isaac         } else {
719797e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
719897e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
719997e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7200a5e93ea8SMatthew G. Knepley               ++cind;
7201a5e93ea8SMatthew G. Knepley             }
7202a5e93ea8SMatthew G. Knepley           }
7203a5e93ea8SMatthew G. Knepley         }
7204a5e93ea8SMatthew G. Knepley       }
7205a5e93ea8SMatthew G. Knepley     }
7206ba322698SMatthew G. Knepley   }
72071a271a75SMatthew G. Knepley   *offset += fdof;
72083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7209a5e93ea8SMatthew G. Knepley }
7210a5e93ea8SMatthew G. Knepley 
7211d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7212d71ae5a4SJacob Faibussowitsch {
7213552f7358SJed Brown   PetscScalar    *array;
72141b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
72151b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
7216552f7358SJed Brown 
72171b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
72189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
72199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
72209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
72219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
72229566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7223b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
7224b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
7225b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
7226b6ebb6e6SMatthew G. Knepley 
72279371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
72289371c9d4SSatish Balay       dof = 0;
72299371c9d4SSatish Balay       continue;
72309371c9d4SSatish Balay     }
72319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
7232b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
7233b6ebb6e6SMatthew G. Knepley     {
7234b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7235b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
7236b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
7237b6ebb6e6SMatthew G. Knepley 
72389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
72399566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
7240b6ebb6e6SMatthew G. Knepley       a = &array[coff];
7241b6ebb6e6SMatthew G. Knepley       if (!cdof) {
7242b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
7243ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
7244b6ebb6e6SMatthew G. Knepley         } else {
7245ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
7246b6ebb6e6SMatthew G. Knepley         }
7247b6ebb6e6SMatthew G. Knepley       } else {
72489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
7249b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
7250b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
72519371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
72529371c9d4SSatish Balay               ++cind;
72539371c9d4SSatish Balay               continue;
72549371c9d4SSatish Balay             }
7255b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
7256b6ebb6e6SMatthew G. Knepley           }
7257b6ebb6e6SMatthew G. Knepley         } else {
7258b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
72599371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
72609371c9d4SSatish Balay               ++cind;
72619371c9d4SSatish Balay               continue;
72629371c9d4SSatish Balay             }
7263b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
7264b6ebb6e6SMatthew G. Knepley           }
7265b6ebb6e6SMatthew G. Knepley         }
7266b6ebb6e6SMatthew G. Knepley       }
7267b6ebb6e6SMatthew G. Knepley     }
7268b6ebb6e6SMatthew G. Knepley   }
72699566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
72703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7271b6ebb6e6SMatthew G. Knepley }
72721b406b76SMatthew G. Knepley 
72731b406b76SMatthew G. Knepley /*@C
727420f4b53cSBarry Smith   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
72751b406b76SMatthew G. Knepley 
72761b406b76SMatthew G. Knepley   Not collective
72771b406b76SMatthew G. Knepley 
72781b406b76SMatthew G. Knepley   Input Parameters:
7279a1cb98faSBarry Smith + dm      - The `DM`
728020f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
72811b406b76SMatthew G. Knepley . v       - The local vector
728220f4b53cSBarry Smith . point   - The point in the `DM`
72831b406b76SMatthew G. Knepley . values  - The array of values
7284a1cb98faSBarry Smith - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
7285a1cb98faSBarry Smith             where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
72861b406b76SMatthew G. Knepley 
72871b406b76SMatthew G. Knepley   Level: intermediate
72881b406b76SMatthew G. Knepley 
7289f13dfd9eSBarry Smith   Note:
7290f13dfd9eSBarry Smith   Usually the input arrays were obtained with `DMPlexVecGetClosure()`
7291f13dfd9eSBarry Smith 
72921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
72931b406b76SMatthew G. Knepley @*/
7294d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7295d71ae5a4SJacob Faibussowitsch {
72961b406b76SMatthew G. Knepley   PetscSection    clSection;
72971b406b76SMatthew G. Knepley   IS              clPoints;
72981b406b76SMatthew G. Knepley   PetscScalar    *array;
72991b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
730027f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
7301c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
73021b406b76SMatthew G. Knepley 
73031a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
73041b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
73059566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
73061a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
73071a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
73089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
73099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
73101b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
73119566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
73123ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
73131b406b76SMatthew G. Knepley   }
73141a271a75SMatthew G. Knepley   /* Get points */
731507218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7316c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
7317c459fbc1SJed Brown     PetscInt dof;
73189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7319c459fbc1SJed Brown     clsize += dof;
7320c459fbc1SJed Brown   }
73219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
73221a271a75SMatthew G. Knepley   /* Get array */
73239566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
73241a271a75SMatthew G. Knepley   /* Get values */
7325ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
732697e99dd9SToby Isaac     PetscInt offset = 0, f;
7327552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
732897e99dd9SToby Isaac       const PetscInt    **perms = NULL;
732997e99dd9SToby Isaac       const PetscScalar **flips = NULL;
733097e99dd9SToby Isaac 
73319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7332552f7358SJed Brown       switch (mode) {
7333552f7358SJed Brown       case INSERT_VALUES:
733497e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
733597e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
733697e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
733797e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73383ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
73399371c9d4SSatish Balay         }
73409371c9d4SSatish Balay         break;
7341552f7358SJed Brown       case INSERT_ALL_VALUES:
734297e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
734397e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
734497e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
734597e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73463ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
73479371c9d4SSatish Balay         }
73489371c9d4SSatish Balay         break;
7349a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
735097e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
735197e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
735297e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
735397e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73543ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
73559371c9d4SSatish Balay         }
73569371c9d4SSatish Balay         break;
7357552f7358SJed Brown       case ADD_VALUES:
735897e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
735997e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
736097e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
736197e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73623ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
73639371c9d4SSatish Balay         }
73649371c9d4SSatish Balay         break;
7365552f7358SJed Brown       case ADD_ALL_VALUES:
736697e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
736797e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
736897e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
736997e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73703ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
73719371c9d4SSatish Balay         }
73729371c9d4SSatish Balay         break;
7373304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
737497e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
737597e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
737697e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
737797e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73783ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
73799371c9d4SSatish Balay         }
73809371c9d4SSatish Balay         break;
7381d71ae5a4SJacob Faibussowitsch       default:
7382d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7383552f7358SJed Brown       }
73849566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
73851a271a75SMatthew G. Knepley     }
7386552f7358SJed Brown   } else {
73871a271a75SMatthew G. Knepley     PetscInt            dof, off;
738897e99dd9SToby Isaac     const PetscInt    **perms = NULL;
738997e99dd9SToby Isaac     const PetscScalar **flips = NULL;
73901a271a75SMatthew G. Knepley 
73919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7392552f7358SJed Brown     switch (mode) {
7393552f7358SJed Brown     case INSERT_VALUES:
739497e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
739597e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
739697e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
739797e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
73989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
73993ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
74009371c9d4SSatish Balay       }
74019371c9d4SSatish Balay       break;
7402552f7358SJed Brown     case INSERT_ALL_VALUES:
740397e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
740497e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
740597e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
740697e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74079566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74083ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
74099371c9d4SSatish Balay       }
74109371c9d4SSatish Balay       break;
7411a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
741297e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
741397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
741497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
741597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74173ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
74189371c9d4SSatish Balay       }
74199371c9d4SSatish Balay       break;
7420552f7358SJed Brown     case ADD_VALUES:
742197e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
742297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
742397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
742497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74259566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74263ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
74279371c9d4SSatish Balay       }
74289371c9d4SSatish Balay       break;
7429552f7358SJed Brown     case ADD_ALL_VALUES:
743097e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
743197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
743297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
743397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74353ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
74369371c9d4SSatish Balay       }
74379371c9d4SSatish Balay       break;
7438304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
743997e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
744097e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
744197e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
744297e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74439566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74443ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
74459371c9d4SSatish Balay       }
74469371c9d4SSatish Balay       break;
7447d71ae5a4SJacob Faibussowitsch     default:
7448d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7449552f7358SJed Brown     }
74509566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7451552f7358SJed Brown   }
74521a271a75SMatthew G. Knepley   /* Cleanup points */
74539566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
74541a271a75SMatthew G. Knepley   /* Cleanup array */
74559566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
74563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7457552f7358SJed Brown }
7458552f7358SJed Brown 
74595f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
7460d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7461d71ae5a4SJacob Faibussowitsch {
74625f790a90SMatthew G. Knepley   PetscFunctionBegin;
746311cc89d2SBarry Smith   *contains = PETSC_TRUE;
74645f790a90SMatthew G. Knepley   if (label) {
7465d6177c40SToby Isaac     PetscInt fdof;
74665f790a90SMatthew G. Knepley 
746711cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
746811cc89d2SBarry Smith     if (!*contains) {
74699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
74705f790a90SMatthew G. Knepley       *offset += fdof;
74713ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
74725f790a90SMatthew G. Knepley     }
74735f790a90SMatthew G. Knepley   }
74743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
74755f790a90SMatthew G. Knepley }
74765f790a90SMatthew G. Knepley 
747797529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7478d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode)
7479d71ae5a4SJacob Faibussowitsch {
7480e07394fbSMatthew G. Knepley   PetscSection    clSection;
7481e07394fbSMatthew G. Knepley   IS              clPoints;
7482e07394fbSMatthew G. Knepley   PetscScalar    *array;
7483e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
748497529cf3SJed Brown   const PetscInt *clp;
7485e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
748697e99dd9SToby Isaac   PetscInt        offset = 0, f;
7487e07394fbSMatthew G. Knepley 
7488e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
7489e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
74909566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7491e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7492e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
74939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7494e07394fbSMatthew G. Knepley   /* Get points */
749507218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7496e07394fbSMatthew G. Knepley   /* Get array */
74979566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7498e07394fbSMatthew G. Knepley   /* Get values */
7499e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
750097e99dd9SToby Isaac     const PetscInt    **perms = NULL;
750197e99dd9SToby Isaac     const PetscScalar **flips = NULL;
750211cc89d2SBarry Smith     PetscBool           contains;
750397e99dd9SToby Isaac 
7504e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
7505e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
7506e07394fbSMatthew G. Knepley         PetscInt fdof;
75079566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7508e07394fbSMatthew G. Knepley         offset += fdof;
7509e07394fbSMatthew G. Knepley       }
7510e07394fbSMatthew G. Knepley       continue;
7511e07394fbSMatthew G. Knepley     }
75129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7513e07394fbSMatthew G. Knepley     switch (mode) {
7514e07394fbSMatthew G. Knepley     case INSERT_VALUES:
751597e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
751697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
751797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
751897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
751911cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
752011cc89d2SBarry Smith         if (!contains) continue;
75219566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
75229371c9d4SSatish Balay       }
75239371c9d4SSatish Balay       break;
7524e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
752597e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
752697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
752797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
752897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
752911cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
753011cc89d2SBarry Smith         if (!contains) continue;
75319566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
75329371c9d4SSatish Balay       }
75339371c9d4SSatish Balay       break;
7534e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
753597e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
753697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
753797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
753897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
753911cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
754011cc89d2SBarry Smith         if (!contains) continue;
75419566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
75429371c9d4SSatish Balay       }
75439371c9d4SSatish Balay       break;
7544e07394fbSMatthew G. Knepley     case ADD_VALUES:
754597e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
754697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
754797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
754897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
754911cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
755011cc89d2SBarry Smith         if (!contains) continue;
75519566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
75529371c9d4SSatish Balay       }
75539371c9d4SSatish Balay       break;
7554e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
755597e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
755697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
755797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
755897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
755911cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
756011cc89d2SBarry Smith         if (!contains) continue;
75619566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
75629371c9d4SSatish Balay       }
75639371c9d4SSatish Balay       break;
7564d71ae5a4SJacob Faibussowitsch     default:
7565d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7566e07394fbSMatthew G. Knepley     }
75679566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7568e07394fbSMatthew G. Knepley   }
7569e07394fbSMatthew G. Knepley   /* Cleanup points */
75709566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7571e07394fbSMatthew G. Knepley   /* Cleanup array */
75729566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
75733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7574e07394fbSMatthew G. Knepley }
7575e07394fbSMatthew G. Knepley 
7576d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7577d71ae5a4SJacob Faibussowitsch {
7578552f7358SJed Brown   PetscMPIInt rank;
7579552f7358SJed Brown   PetscInt    i, j;
7580552f7358SJed Brown 
7581552f7358SJed Brown   PetscFunctionBegin;
75829566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
758363a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
758463a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
758563a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7586b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
75873ba16761SJacob Faibussowitsch   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7588b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
75899566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7590b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
7591519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
75929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7593552f7358SJed Brown #else
75949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7595552f7358SJed Brown #endif
7596552f7358SJed Brown     }
75979566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7598552f7358SJed Brown   }
75993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7600552f7358SJed Brown }
7601552f7358SJed Brown 
760205586334SMatthew G. Knepley /*
760305586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
760405586334SMatthew G. Knepley 
760505586334SMatthew G. Knepley   Input Parameters:
760605586334SMatthew G. Knepley + section - The section for this data layout
760736fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
760805586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
760905586334SMatthew G. Knepley . off     - The global offset of this point
761005586334SMatthew G. Knepley . loff    - The local offset of each field
7611a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
761205586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
761305586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
761405586334SMatthew G. Knepley 
761505586334SMatthew G. Knepley   Output Parameter:
761605586334SMatthew G. Knepley . indices - Indices for dofs on this point
761705586334SMatthew G. Knepley 
761805586334SMatthew G. Knepley   Level: developer
761905586334SMatthew G. Knepley 
762005586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
762105586334SMatthew G. Knepley */
7622d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7623d71ae5a4SJacob Faibussowitsch {
7624e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
7625552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
7626552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7627552f7358SJed Brown   PetscInt        cind = 0, k;
7628552f7358SJed Brown 
7629552f7358SJed Brown   PetscFunctionBegin;
763008401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
76319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
76329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7633552f7358SJed Brown   if (!cdof || setBC) {
763405586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
763505586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
763605586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
763705586334SMatthew G. Knepley 
763805586334SMatthew G. Knepley       indices[ind] = off + k;
7639552f7358SJed Brown     }
7640552f7358SJed Brown   } else {
76419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
76424acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
764305586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
764405586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
764505586334SMatthew G. Knepley 
76464acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
76474acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
764805586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
76494acb8e1eSToby Isaac         ++cind;
76504acb8e1eSToby Isaac       } else {
765136fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
7652552f7358SJed Brown       }
7653552f7358SJed Brown     }
7654552f7358SJed Brown   }
7655e6ccafaeSMatthew G Knepley   *loff += dof;
76563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7657552f7358SJed Brown }
7658552f7358SJed Brown 
76597e29afd2SMatthew G. Knepley /*
766036fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
76617e29afd2SMatthew G. Knepley 
766236fa2b79SJed Brown  Input Parameters:
766336fa2b79SJed Brown + section - a section (global or local)
766420f4b53cSBarry Smith - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
766536fa2b79SJed Brown . point - point within section
766636fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
766736fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
766836fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
766936fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
767036fa2b79SJed Brown . permsoff - offset
767136fa2b79SJed Brown - indperm - index permutation
767236fa2b79SJed Brown 
767336fa2b79SJed Brown  Output Parameter:
767436fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
767536fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
767636fa2b79SJed Brown 
767736fa2b79SJed Brown  Notes:
767836fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
767936fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
768036fa2b79SJed Brown  in the local vector.
768136fa2b79SJed Brown 
768236fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
768336fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
768436fa2b79SJed Brown 
768536fa2b79SJed Brown  Developer Note:
768636fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
768736fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
768836fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
768936fa2b79SJed Brown 
769036fa2b79SJed Brown  Example:
769136fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
769236fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
769336fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
769436fa2b79SJed 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.
769536fa2b79SJed Brown 
769636fa2b79SJed Brown  Level: developer
76977e29afd2SMatthew G. Knepley */
7698d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7699d71ae5a4SJacob Faibussowitsch {
7700552f7358SJed Brown   PetscInt numFields, foff, f;
7701552f7358SJed Brown 
7702552f7358SJed Brown   PetscFunctionBegin;
770308401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
77049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7705552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
77064acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
7707552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
77084acb8e1eSToby Isaac     PetscInt        cind = 0, b;
77094acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7710552f7358SJed Brown 
77119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
77129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7713552f7358SJed Brown     if (!cfdof || setBC) {
771405586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
771505586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
771605586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
771705586334SMatthew G. Knepley 
771805586334SMatthew G. Knepley         indices[ind] = off + foff + b;
771905586334SMatthew G. Knepley       }
7720552f7358SJed Brown     } else {
77219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
772205586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
772305586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
772405586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
772505586334SMatthew G. Knepley 
77264acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
772705586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
7728552f7358SJed Brown           ++cind;
7729552f7358SJed Brown         } else {
773036fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7731552f7358SJed Brown         }
7732552f7358SJed Brown       }
7733552f7358SJed Brown     }
773436fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7735552f7358SJed Brown     foffs[f] += fdof;
7736552f7358SJed Brown   }
77373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7738552f7358SJed Brown }
7739552f7358SJed Brown 
77407e29afd2SMatthew G. Knepley /*
77417e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
77427e29afd2SMatthew G. Knepley 
77437e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7744645102dcSJed Brown 
7745645102dcSJed Brown  Notes:
7746645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7747645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
77487e29afd2SMatthew G. Knepley */
7749d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7750d71ae5a4SJacob Faibussowitsch {
77517e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
77527e29afd2SMatthew G. Knepley 
77537e29afd2SMatthew G. Knepley   PetscFunctionBegin;
77549566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
77557e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
77567e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
77577e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
77587e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
77597e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
77607e29afd2SMatthew G. Knepley 
77619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
77629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
77639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7764645102dcSJed Brown     if (!cfdof) {
776505586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
776605586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
776705586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
776805586334SMatthew G. Knepley 
776905586334SMatthew G. Knepley         indices[ind] = foff + b;
777005586334SMatthew G. Knepley       }
77717e29afd2SMatthew G. Knepley     } else {
77729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
777305586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
777405586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
777505586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
777605586334SMatthew G. Knepley 
77777e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
777805586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
77797e29afd2SMatthew G. Knepley           ++cind;
77807e29afd2SMatthew G. Knepley         } else {
778105586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
77827e29afd2SMatthew G. Knepley         }
77837e29afd2SMatthew G. Knepley       }
77847e29afd2SMatthew G. Knepley     }
77857e29afd2SMatthew G. Knepley     foffs[f] += fdof;
77867e29afd2SMatthew G. Knepley   }
77873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
77887e29afd2SMatthew G. Knepley }
77897e29afd2SMatthew G. Knepley 
7790c789d87fSToby Isaac static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms)
7791c789d87fSToby Isaac {
7792c789d87fSToby Isaac   PetscInt numFields, sStart, sEnd, cStart, cEnd;
7793c789d87fSToby Isaac 
7794c789d87fSToby Isaac   PetscFunctionBegin;
7795c789d87fSToby Isaac   PetscCall(PetscSectionGetNumFields(section, &numFields));
7796c789d87fSToby Isaac   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7797c789d87fSToby Isaac   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7798c789d87fSToby Isaac   for (PetscInt p = 0; p < nPoints; p++) {
7799c789d87fSToby Isaac     PetscInt     b       = pnts[2 * p];
7800c789d87fSToby Isaac     PetscInt     bSecDof = 0, bOff;
7801c789d87fSToby Isaac     PetscInt     cSecDof = 0;
7802c789d87fSToby Isaac     PetscSection indices_section;
7803c789d87fSToby Isaac 
7804c789d87fSToby Isaac     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7805c789d87fSToby Isaac     if (!bSecDof) continue;
7806c789d87fSToby Isaac     if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof));
7807c789d87fSToby Isaac     indices_section = cSecDof > 0 ? cSec : section;
7808c789d87fSToby Isaac     if (numFields) {
7809c789d87fSToby Isaac       PetscInt fStart[32], fEnd[32];
7810c789d87fSToby Isaac 
7811c789d87fSToby Isaac       fStart[0] = 0;
7812c789d87fSToby Isaac       fEnd[0]   = 0;
7813c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7814c789d87fSToby Isaac         PetscInt fDof = 0;
7815c789d87fSToby Isaac 
7816c789d87fSToby Isaac         PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof));
7817c789d87fSToby Isaac         fStart[f + 1] = fStart[f] + fDof;
7818c789d87fSToby Isaac         fEnd[f + 1]   = fStart[f + 1];
7819c789d87fSToby Isaac       }
7820c789d87fSToby Isaac       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7821c789d87fSToby Isaac       // only apply permutations on one side
7822c789d87fSToby Isaac       PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices));
7823c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7824ac530a7eSPierre Jolivet         for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7825c789d87fSToby Isaac       }
7826c789d87fSToby Isaac     } else {
7827c789d87fSToby Isaac       PetscInt bEnd = 0;
7828c789d87fSToby Isaac 
7829c789d87fSToby Isaac       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7830c789d87fSToby Isaac       PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices));
7831c789d87fSToby Isaac 
7832c789d87fSToby Isaac       for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7833c789d87fSToby Isaac     }
7834c789d87fSToby Isaac   }
7835c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
7836c789d87fSToby Isaac }
7837c789d87fSToby Isaac 
7838c789d87fSToby Isaac PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[])
7839d71ae5a4SJacob Faibussowitsch {
7840d3d1a6afSToby Isaac   Mat             cMat;
7841d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7842d3d1a6afSToby Isaac   IS              aIS;
7843d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7844a19ea1e9SMatthew G. Knepley   PetscInt        sStart = -1, sEnd = -1;
7845a19ea1e9SMatthew G. Knepley   PetscInt        cStart = -1, cEnd = -1;
7846d3d1a6afSToby Isaac   const PetscInt *anchors;
7847e969e7a5SJose E. Roman   PetscInt        numFields, p;
7848d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7849c789d87fSToby Isaac   PetscInt       *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices;
7850c789d87fSToby Isaac   PetscInt        oldOffsets[32];
7851d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7852c789d87fSToby Isaac   PetscInt        oldOffsetsCopy[32];
7853c789d87fSToby Isaac   PetscInt        newOffsetsCopy[32];
7854c789d87fSToby Isaac   PetscScalar    *modMat         = NULL;
7855d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7856d3d1a6afSToby Isaac 
7857d3d1a6afSToby Isaac   PetscFunctionBegin;
7858d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7859d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
78609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7861d3d1a6afSToby Isaac 
78629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7863d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7864d3d1a6afSToby Isaac   if (aSec) {
78659566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
7866c789d87fSToby Isaac     PetscCall(PetscArrayzero(oldOffsets, 32));
78679566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
78689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7869a19ea1e9SMatthew G. Knepley     PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7870d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7871d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7872d3d1a6afSToby Isaac      * into the global matrix anyway) */
7873d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7874d3d1a6afSToby Isaac       PetscInt b    = points[p];
7875a19ea1e9SMatthew G. Knepley       PetscInt bDof = 0, bSecDof = 0;
7876d3d1a6afSToby Isaac 
7877a19ea1e9SMatthew G. Knepley       if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7878ad540459SPierre Jolivet       if (!bSecDof) continue;
7879c789d87fSToby Isaac 
7880c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7881c789d87fSToby Isaac         PetscInt fDof = 0;
7882c789d87fSToby Isaac 
7883c789d87fSToby Isaac         PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7884c789d87fSToby Isaac         oldOffsets[f + 1] += fDof;
7885c789d87fSToby Isaac       }
788648a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7887d3d1a6afSToby Isaac       if (bDof) {
7888d3d1a6afSToby Isaac         /* this point is constrained */
7889d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7890d3d1a6afSToby Isaac         PetscInt bOff, q;
7891d3d1a6afSToby Isaac 
78929566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7893d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7894d3d1a6afSToby Isaac           PetscInt a    = anchors[bOff + q];
7895a19ea1e9SMatthew G. Knepley           PetscInt aDof = 0;
7896d3d1a6afSToby Isaac 
7897a19ea1e9SMatthew G. Knepley           if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7898c789d87fSToby Isaac           if (aDof) {
7899c789d87fSToby Isaac             anyConstrained = PETSC_TRUE;
7900c789d87fSToby Isaac             newNumPoints += 1;
7901c789d87fSToby Isaac           }
7902d3d1a6afSToby Isaac           newNumIndices += aDof;
7903e969e7a5SJose E. Roman           for (PetscInt f = 0; f < numFields; ++f) {
7904a19ea1e9SMatthew G. Knepley             PetscInt fDof = 0;
7905d3d1a6afSToby Isaac 
7906a19ea1e9SMatthew G. Knepley             if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7907d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7908d3d1a6afSToby Isaac           }
7909d3d1a6afSToby Isaac         }
79109371c9d4SSatish Balay       } else {
7911d3d1a6afSToby Isaac         /* this point is not constrained */
7912d3d1a6afSToby Isaac         newNumPoints++;
79134b2f2278SToby Isaac         newNumIndices += bSecDof;
7914e969e7a5SJose E. Roman         for (PetscInt f = 0; f < numFields; ++f) {
7915d3d1a6afSToby Isaac           PetscInt fDof;
7916d3d1a6afSToby Isaac 
79179566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7918d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7919d3d1a6afSToby Isaac         }
7920d3d1a6afSToby Isaac       }
7921d3d1a6afSToby Isaac     }
7922d3d1a6afSToby Isaac   }
7923d3d1a6afSToby Isaac   if (!anyConstrained) {
792472b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
792572b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
792672b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
7927c789d87fSToby Isaac     if (outMat) *outMat = NULL;
79289566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
79293ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7930d3d1a6afSToby Isaac   }
7931d3d1a6afSToby Isaac 
79326ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
79336ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
79346ecaa68aSToby Isaac 
7935e969e7a5SJose E. Roman   for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7936e969e7a5SJose E. Roman   for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f];
7937d3d1a6afSToby Isaac 
7938c789d87fSToby Isaac   if (!outPoints && !outMat) {
79396ecaa68aSToby Isaac     if (offsets) {
7940e969e7a5SJose E. Roman       for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
79416ecaa68aSToby Isaac     }
79429566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
79433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
79446ecaa68aSToby Isaac   }
79456ecaa68aSToby Isaac 
79461dca8a05SBarry 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);
7947c789d87fSToby Isaac   PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices);
7948d3d1a6afSToby Isaac 
79499566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7950a19ea1e9SMatthew G. Knepley   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7951d3d1a6afSToby Isaac 
79526ecaa68aSToby Isaac   /* output arrays */
79539566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7954c789d87fSToby Isaac   PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints));
79556ecaa68aSToby Isaac 
7956c789d87fSToby Isaac   // get the new Points
7957c789d87fSToby Isaac   for (PetscInt p = 0, newP = 0; p < numPoints; p++) {
7958d3d1a6afSToby Isaac     PetscInt b    = points[2 * p];
7959c789d87fSToby Isaac     PetscInt bDof = 0, bSecDof = 0, bOff;
7960d3d1a6afSToby Isaac 
7961a19ea1e9SMatthew G. Knepley     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7962ad540459SPierre Jolivet     if (!bSecDof) continue;
796348a46eb9SPierre Jolivet     if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7964d3d1a6afSToby Isaac     if (bDof) {
79659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7966c789d87fSToby Isaac       for (PetscInt q = 0; q < bDof; q++) {
7967a19ea1e9SMatthew G. Knepley         PetscInt a = anchors[bOff + q], aDof = 0;
7968d3d1a6afSToby Isaac 
7969a19ea1e9SMatthew G. Knepley         if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7970c789d87fSToby Isaac         if (aDof) {
7971c789d87fSToby Isaac           newPoints[2 * newP]     = a;
7972c789d87fSToby Isaac           newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation
7973d3d1a6afSToby Isaac           newP++;
7974d3d1a6afSToby Isaac         }
7975d3d1a6afSToby Isaac       }
7976d3d1a6afSToby Isaac     } else {
7977d3d1a6afSToby Isaac       newPoints[2 * newP]     = b;
7978c789d87fSToby Isaac       newPoints[2 * newP + 1] = points[2 * p + 1];
7979d3d1a6afSToby Isaac       newP++;
7980d3d1a6afSToby Isaac     }
7981d3d1a6afSToby Isaac   }
7982d3d1a6afSToby Isaac 
7983c789d87fSToby Isaac   if (outMat) {
7984c789d87fSToby Isaac     PetscScalar *tmpMat;
7985c789d87fSToby Isaac     PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32));
7986c789d87fSToby Isaac     PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32));
7987c789d87fSToby Isaac 
7988c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices));
7989c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7990c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7991c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7992c789d87fSToby Isaac 
7993c789d87fSToby Isaac     for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1;
7994c789d87fSToby Isaac     for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1;
7995c789d87fSToby Isaac 
7996c789d87fSToby Isaac     PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms));
7997c789d87fSToby Isaac     PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL));
7998c789d87fSToby Isaac 
7999c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
8000c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
8001c789d87fSToby Isaac     PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices));
8002c789d87fSToby Isaac     // for each field, insert the anchor modification into modMat
8003c789d87fSToby Isaac     for (PetscInt f = 0; f < PetscMax(1, numFields); f++) {
8004c789d87fSToby Isaac       PetscInt fStart    = oldOffsets[f];
8005c789d87fSToby Isaac       PetscInt fNewStart = newOffsets[f];
8006e60de12fSPierre Jolivet       for (PetscInt p = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) {
8007c789d87fSToby Isaac         PetscInt b    = points[2 * p];
8008c789d87fSToby Isaac         PetscInt bDof = 0, bSecDof = 0, bOff;
8009c789d87fSToby Isaac 
8010c789d87fSToby Isaac         if (b >= sStart && b < sEnd) {
8011d3d1a6afSToby Isaac           if (numFields) {
8012c789d87fSToby Isaac             PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof));
80139371c9d4SSatish Balay           } else {
8014c789d87fSToby Isaac             PetscCall(PetscSectionGetDof(section, b, &bSecDof));
8015d3d1a6afSToby Isaac           }
8016d3d1a6afSToby Isaac         }
8017c789d87fSToby Isaac         if (!bSecDof) continue;
8018c789d87fSToby Isaac         if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
8019c789d87fSToby Isaac         if (bDof) {
8020c789d87fSToby Isaac           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
8021e60de12fSPierre Jolivet           for (PetscInt q = 0; q < bDof; q++) {
8022c789d87fSToby Isaac             PetscInt a = anchors[bOff + q], aDof = 0;
8023d3d1a6afSToby Isaac 
8024c789d87fSToby Isaac             if (a >= sStart && a < sEnd) {
8025d3d1a6afSToby Isaac               if (numFields) {
8026c789d87fSToby Isaac                 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
8027c789d87fSToby Isaac               } else {
8028c789d87fSToby Isaac                 PetscCall(PetscSectionGetDof(section, a, &aDof));
8029d3d1a6afSToby Isaac               }
8030d3d1a6afSToby Isaac             }
8031c789d87fSToby Isaac             if (aDof) {
8032c789d87fSToby Isaac               PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat));
8033c789d87fSToby Isaac               for (PetscInt d = 0; d < bSecDof; d++) {
8034c789d87fSToby Isaac                 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e];
8035c789d87fSToby Isaac               }
8036c789d87fSToby Isaac             }
8037c789d87fSToby Isaac             oNew += aDof;
8038c789d87fSToby Isaac           }
80399371c9d4SSatish Balay         } else {
8040c789d87fSToby Isaac           // Insert the identity matrix in this block
8041c789d87fSToby Isaac           for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1;
8042c789d87fSToby Isaac           oNew += bSecDof;
8043d3d1a6afSToby Isaac         }
8044c789d87fSToby Isaac         o += bSecDof;
8045d3d1a6afSToby Isaac       }
8046d3d1a6afSToby Isaac     }
8047d3d1a6afSToby Isaac 
8048c789d87fSToby Isaac     *outMat = modMat;
80496ecaa68aSToby Isaac 
8050c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
8051c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
8052c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
8053c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
8054c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices));
8055d3d1a6afSToby Isaac   }
80569566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
8057d3d1a6afSToby Isaac 
8058d3d1a6afSToby Isaac   /* output */
80596ecaa68aSToby Isaac   if (outPoints) {
8060d3d1a6afSToby Isaac     *outPoints = newPoints;
80619371c9d4SSatish Balay   } else {
80629566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
80636ecaa68aSToby Isaac   }
8064e969e7a5SJose E. Roman   for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
80653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8066d3d1a6afSToby Isaac }
8067d3d1a6afSToby Isaac 
8068c789d87fSToby Isaac PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft)
8069c789d87fSToby Isaac {
8070c789d87fSToby Isaac   PetscScalar *modMat        = NULL;
8071c789d87fSToby Isaac   PetscInt     newNumIndices = -1;
80727cd05799SMatthew G. Knepley 
8073c789d87fSToby Isaac   PetscFunctionBegin;
8074c789d87fSToby Isaac   /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix.
8075c789d87fSToby Isaac      modMat is that matrix C */
8076c789d87fSToby Isaac   PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL));
8077c789d87fSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
8078c789d87fSToby Isaac   if (modMat) {
8079c789d87fSToby Isaac     const PetscScalar *newValues = values;
80807cd05799SMatthew G. Knepley 
8081c789d87fSToby Isaac     if (multiplyRight) {
8082c789d87fSToby Isaac       PetscScalar *newNewValues = NULL;
80836497c311SBarry Smith       PetscBLASInt M, N, K;
8084c789d87fSToby Isaac       PetscScalar  a = 1.0, b = 0.0;
80857cd05799SMatthew G. Knepley 
8086c789d87fSToby Isaac       PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices);
80877cd05799SMatthew G. Knepley 
80886497c311SBarry Smith       PetscCall(PetscBLASIntCast(newNumIndices, &M));
80896497c311SBarry Smith       PetscCall(PetscBLASIntCast(numRows, &N));
80906497c311SBarry Smith       PetscCall(PetscBLASIntCast(numIndices, &K));
8091c789d87fSToby Isaac       PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues));
8092c789d87fSToby Isaac       // row-major to column-major conversion, right multiplication becomes left multiplication
8093c789d87fSToby Isaac       PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M));
8094c789d87fSToby Isaac       numCols   = newNumIndices;
8095c789d87fSToby Isaac       newValues = newNewValues;
8096c789d87fSToby Isaac     }
8097a1cb98faSBarry Smith 
8098c789d87fSToby Isaac     if (multiplyLeft) {
8099c789d87fSToby Isaac       PetscScalar *newNewValues = NULL;
81006497c311SBarry Smith       PetscBLASInt M, N, K;
8101c789d87fSToby Isaac       PetscScalar  a = 1.0, b = 0.0;
81027cd05799SMatthew G. Knepley 
8103c789d87fSToby Isaac       PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices);
8104c789d87fSToby Isaac 
81056497c311SBarry Smith       PetscCall(PetscBLASIntCast(numCols, &M));
81066497c311SBarry Smith       PetscCall(PetscBLASIntCast(newNumIndices, &N));
81076497c311SBarry Smith       PetscCall(PetscBLASIntCast(numIndices, &K));
8108c789d87fSToby Isaac       PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues));
8109c789d87fSToby Isaac       // row-major to column-major conversion, left multiplication becomes right multiplication
8110c789d87fSToby Isaac       PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M));
8111c789d87fSToby Isaac       if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues));
8112c789d87fSToby Isaac       newValues = newNewValues;
8113c789d87fSToby Isaac     }
8114c789d87fSToby Isaac     *outValues = (PetscScalar *)newValues;
8115c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
8116c789d87fSToby Isaac   }
8117c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
8118c789d87fSToby Isaac }
8119c789d87fSToby Isaac 
8120c789d87fSToby Isaac PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
8121c789d87fSToby Isaac {
8122c789d87fSToby Isaac   PetscFunctionBegin;
8123c789d87fSToby Isaac   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft));
8124c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
8125c789d87fSToby Isaac }
8126c789d87fSToby Isaac 
8127c789d87fSToby Isaac static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize)
8128c789d87fSToby Isaac {
8129c789d87fSToby Isaac   /* Closure ordering */
8130c789d87fSToby Isaac   PetscSection    clSection;
8131c789d87fSToby Isaac   IS              clPoints;
8132c789d87fSToby Isaac   const PetscInt *clp;
8133c789d87fSToby Isaac   PetscInt       *points;
8134c789d87fSToby Isaac   PetscInt        Ncl, Ni = 0;
8135c789d87fSToby Isaac 
8136c789d87fSToby Isaac   PetscFunctionBeginHot;
8137c789d87fSToby Isaac   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
8138c789d87fSToby Isaac   for (PetscInt p = 0; p < Ncl * 2; p += 2) {
8139c789d87fSToby Isaac     PetscInt dof;
8140c789d87fSToby Isaac 
8141c789d87fSToby Isaac     PetscCall(PetscSectionGetDof(section, points[p], &dof));
8142c789d87fSToby Isaac     Ni += dof;
8143c789d87fSToby Isaac   }
8144c789d87fSToby Isaac   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
8145c789d87fSToby Isaac   *closureSize = Ni;
8146c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
8147c789d87fSToby Isaac }
8148c789d87fSToby Isaac 
8149c789d87fSToby Isaac static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft)
8150d71ae5a4SJacob Faibussowitsch {
815171f0bbf9SMatthew G. Knepley   /* Closure ordering */
81527773e69fSMatthew G. Knepley   PetscSection    clSection;
81537773e69fSMatthew G. Knepley   IS              clPoints;
815471f0bbf9SMatthew G. Knepley   const PetscInt *clp;
815571f0bbf9SMatthew G. Knepley   PetscInt       *points;
815671f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
815771f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
81584acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
815971f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
816071f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
816171f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
816271f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
816371f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
816471f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
816571f0bbf9SMatthew G. Knepley 
816671f0bbf9SMatthew G. Knepley   PetscInt *idx;
816771f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
816871f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
81697caea556SToby Isaac   PetscInt  idxStart, idxEnd;
8170c789d87fSToby Isaac   PetscInt  nRows, nCols;
81717773e69fSMatthew G. Knepley 
817271f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
81737773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81747773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
817536fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
8176c789d87fSToby Isaac   PetscAssertPointer(numRows, 6);
8177c789d87fSToby Isaac   PetscAssertPointer(numCols, 7);
8178c789d87fSToby Isaac   if (indices) PetscAssertPointer(indices, 8);
8179c789d87fSToby Isaac   if (outOffsets) PetscAssertPointer(outOffsets, 9);
8180c789d87fSToby Isaac   if (values) PetscAssertPointer(values, 10);
81819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
818263a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
81839566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
818471f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
818507218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
8186c459fbc1SJed Brown   if (useClPerm) {
8187c459fbc1SJed Brown     PetscInt depth, clsize;
81889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
8189c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
8190c459fbc1SJed Brown       PetscInt dof;
81919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
8192c459fbc1SJed Brown       clsize += dof;
8193c459fbc1SJed Brown     }
81949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
8195c459fbc1SJed Brown   }
819671f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
819771f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
81987773e69fSMatthew G. Knepley     PetscInt dof, fdof;
81997773e69fSMatthew G. Knepley 
82009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
82017773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
82029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
82037773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
82047773e69fSMatthew G. Knepley     }
820571f0bbf9SMatthew G. Knepley     Ni += dof;
82067773e69fSMatthew G. Knepley   }
8207c789d87fSToby Isaac   if (*numRows == -1) *numRows = Ni;
8208c789d87fSToby Isaac   if (*numCols == -1) *numCols = Ni;
8209c789d87fSToby Isaac   nRows = *numRows;
8210c789d87fSToby Isaac   nCols = *numCols;
82117773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
82121dca8a05SBarry 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);
821371f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
8214c789d87fSToby Isaac   if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols);
8215c789d87fSToby Isaac   if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows);
821671f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
82179566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
82189566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
821971f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
822071f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
822171f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
82226ecaa68aSToby Isaac 
822371f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
822471f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
822571f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
822671f0bbf9SMatthew G. Knepley 
82279566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
82289566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
822971f0bbf9SMatthew G. Knepley         if (flip) {
823071f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
823171f0bbf9SMatthew G. Knepley 
823271f0bbf9SMatthew G. Knepley           if (!valCopy) {
82339566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
823471f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
823571f0bbf9SMatthew G. Knepley             *values = valCopy;
823671f0bbf9SMatthew G. Knepley           }
823771f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
823871f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
823971f0bbf9SMatthew G. Knepley 
8240c789d87fSToby Isaac             if (multiplyRight) {
8241ac530a7eSPierre Jolivet               for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval;
8242c789d87fSToby Isaac             }
8243c789d87fSToby Isaac             if (multiplyLeft) {
8244ac530a7eSPierre Jolivet               for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval;
82456ecaa68aSToby Isaac             }
82466ecaa68aSToby Isaac           }
824771f0bbf9SMatthew G. Knepley         }
824871f0bbf9SMatthew G. Knepley         foffset += fdof;
824971f0bbf9SMatthew G. Knepley       }
825071f0bbf9SMatthew G. Knepley     }
825171f0bbf9SMatthew G. Knepley   }
825271f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
8253c789d87fSToby Isaac   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft));
825471f0bbf9SMatthew G. Knepley   if (NclC) {
825563bfac88SBarry Smith     if (multiplyRight) *numCols = NiC;
825663bfac88SBarry Smith     if (multiplyLeft) *numRows = NiC;
82579566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
825871f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
82599566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
82609566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
826171f0bbf9SMatthew G. Knepley     }
826271f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
82639566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
82649566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
826571f0bbf9SMatthew G. Knepley     }
82669566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
826771f0bbf9SMatthew G. Knepley     Ncl    = NclC;
826871f0bbf9SMatthew G. Knepley     Ni     = NiC;
826971f0bbf9SMatthew G. Knepley     points = pointsC;
827071f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
827171f0bbf9SMatthew G. Knepley   }
827271f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
82739566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
82747caea556SToby Isaac   PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd));
827571f0bbf9SMatthew G. Knepley   if (Nf) {
827671f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
827771f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
827871f0bbf9SMatthew G. Knepley 
82799371c9d4SSatish Balay     if (outOffsets) {
82809371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
82819371c9d4SSatish Balay     }
82829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
828371f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
828471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
828571f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
828671f0bbf9SMatthew G. Knepley 
82879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
82887773e69fSMatthew G. Knepley       }
82897773e69fSMatthew G. Knepley     } else {
829071f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
829171f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
829271f0bbf9SMatthew G. Knepley 
82937caea556SToby Isaac         if (pnt < idxStart || pnt >= idxEnd) continue;
82949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
829571f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
829671f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
829771f0bbf9SMatthew G. Knepley          * global section. */
82989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
829971f0bbf9SMatthew G. Knepley       }
830071f0bbf9SMatthew G. Knepley     }
830171f0bbf9SMatthew G. Knepley   } else {
830271f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
830371f0bbf9SMatthew G. Knepley 
830471f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
830571f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
83064acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
83074acb8e1eSToby Isaac 
83087caea556SToby Isaac       if (pnt < idxStart || pnt >= idxEnd) continue;
83099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
831071f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
831171f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
83129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
83137773e69fSMatthew G. Knepley     }
83147773e69fSMatthew G. Knepley   }
831571f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
831671f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
83179566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
83189566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
83194acb8e1eSToby Isaac   }
832071f0bbf9SMatthew G. Knepley   if (NclC) {
83219566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
83227773e69fSMatthew G. Knepley   } else {
83239566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
83247773e69fSMatthew G. Knepley   }
832571f0bbf9SMatthew G. Knepley 
832671f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
83273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83287773e69fSMatthew G. Knepley }
83297773e69fSMatthew G. Knepley 
8330d3d1a6afSToby Isaac /*@C
8331d3d1a6afSToby Isaac   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
8332d3d1a6afSToby Isaac 
8333d3d1a6afSToby Isaac   Not collective
8334d3d1a6afSToby Isaac 
8335d3d1a6afSToby Isaac   Input Parameters:
8336d3d1a6afSToby Isaac + dm         - The `DM`
8337d3d1a6afSToby Isaac . section    - The `PetscSection` describing the points (a local section)
8338d3d1a6afSToby Isaac . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
8339d3d1a6afSToby Isaac . point      - The point defining the closure
8340d3d1a6afSToby Isaac - useClPerm  - Use the closure point permutation if available
8341d3d1a6afSToby Isaac 
8342d3d1a6afSToby Isaac   Output Parameters:
8343d3d1a6afSToby Isaac + numIndices - The number of dof indices in the closure of point with the input sections
8344d3d1a6afSToby Isaac . indices    - The dof indices
8345c3871b17SNoam T . outOffsets - Array, of length the number of fields plus 1, to write the field offsets into, or `NULL`
8346d3d1a6afSToby Isaac - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
8347d3d1a6afSToby Isaac 
8348d3d1a6afSToby Isaac   Level: advanced
8349d3d1a6afSToby Isaac 
8350d3d1a6afSToby Isaac   Notes:
83512c9a7b26SBarry Smith   Call `DMPlexRestoreClosureIndices()` to free allocated memory
8352d3d1a6afSToby Isaac 
8353d3d1a6afSToby Isaac   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
8354d3d1a6afSToby Isaac   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
8355d3d1a6afSToby Isaac   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
8356d3d1a6afSToby Isaac   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
8357d3d1a6afSToby Isaac   indices (with the above semantics) are implied.
8358d3d1a6afSToby Isaac 
8359d3d1a6afSToby Isaac .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
8360d3d1a6afSToby Isaac           `PetscSection`, `DMGetGlobalSection()`
8361d3d1a6afSToby Isaac @*/
8362ce78bad3SBarry Smith PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[])
8363d3d1a6afSToby Isaac {
8364c789d87fSToby Isaac   PetscInt numRows = -1, numCols = -1;
8365d3d1a6afSToby Isaac 
8366d3d1a6afSToby Isaac   PetscFunctionBeginHot;
8367c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE));
8368c789d87fSToby Isaac   PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols);
8369c789d87fSToby Isaac   *numIndices = numRows;
83707773e69fSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
83717773e69fSMatthew G. Knepley }
83727773e69fSMatthew G. Knepley 
83737cd05799SMatthew G. Knepley /*@C
837471f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
83757cd05799SMatthew G. Knepley 
83767cd05799SMatthew G. Knepley   Not collective
83777cd05799SMatthew G. Knepley 
83787cd05799SMatthew G. Knepley   Input Parameters:
8379a1cb98faSBarry Smith + dm         - The `DM`
8380a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
8381a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
838271f0bbf9SMatthew G. Knepley . point      - The point defining the closure
838371f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
838471f0bbf9SMatthew G. Knepley 
838571f0bbf9SMatthew G. Knepley   Output Parameters:
838671f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
838771f0bbf9SMatthew G. Knepley . indices    - The dof indices
838820f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
838920f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
839071f0bbf9SMatthew G. Knepley 
8391a1cb98faSBarry Smith   Level: advanced
839271f0bbf9SMatthew G. Knepley 
8393a1cb98faSBarry Smith   Notes:
8394a1cb98faSBarry Smith   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
8395a1cb98faSBarry Smith 
8396a1cb98faSBarry Smith   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
839771f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
839871f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
839971f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
840071f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
84017cd05799SMatthew G. Knepley 
84021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
84037cd05799SMatthew G. Knepley @*/
8404ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[])
8405d71ae5a4SJacob Faibussowitsch {
84067773e69fSMatthew G. Knepley   PetscFunctionBegin;
84077773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84084f572ea9SToby Isaac   PetscAssertPointer(indices, 7);
84099566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
84103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84117773e69fSMatthew G. Knepley }
84127773e69fSMatthew G. Knepley 
8413e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8414d71ae5a4SJacob Faibussowitsch {
8415552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
8416552f7358SJed Brown   PetscInt          *indices;
841771f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
841871f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
8419552f7358SJed Brown   PetscErrorCode     ierr;
8420552f7358SJed Brown 
8421552f7358SJed Brown   PetscFunctionBegin;
8422552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84239566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
84243dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
84259566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
84263dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
8427e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 5);
8428552f7358SJed Brown 
8429e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
84300d644c17SKarl Rupp 
84319566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
8432d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
84334a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8434552f7358SJed Brown   if (ierr) {
8435552f7358SJed Brown     PetscMPIInt rank;
8436552f7358SJed Brown 
84379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
84389566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
84399566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
84409566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
84419566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8442c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
8443552f7358SJed Brown   }
84444a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
84454a1e0b3eSMatthew G. Knepley     PetscInt i;
84469566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
844763a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
84489566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
84494a1e0b3eSMatthew G. Knepley   }
845071f0bbf9SMatthew G. Knepley 
84519566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
84529566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
84533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84544acb8e1eSToby Isaac }
845571f0bbf9SMatthew G. Knepley 
84564a1e0b3eSMatthew G. Knepley /*@C
8457e8e188d2SZach Atkins   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
8458e8e188d2SZach Atkins 
8459e8e188d2SZach Atkins   Not collective
8460e8e188d2SZach Atkins 
8461e8e188d2SZach Atkins   Input Parameters:
8462e8e188d2SZach Atkins + dm            - The `DM`
8463e8e188d2SZach Atkins . section       - The section describing the layout in `v`, or `NULL` to use the default section
8464e8e188d2SZach Atkins . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
8465e8e188d2SZach Atkins . A             - The matrix
8466e8e188d2SZach Atkins . point         - The point in the `DM`
8467e8e188d2SZach Atkins . values        - The array of values
8468e8e188d2SZach Atkins - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8469e8e188d2SZach Atkins 
8470e8e188d2SZach Atkins   Level: intermediate
8471e8e188d2SZach Atkins 
8472e8e188d2SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8473e8e188d2SZach Atkins @*/
8474e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8475e8e188d2SZach Atkins {
8476e8e188d2SZach Atkins   PetscFunctionBegin;
8477e8e188d2SZach Atkins   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
8478e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
8479e8e188d2SZach Atkins }
8480e8e188d2SZach Atkins 
8481e8e188d2SZach Atkins /*@C
848260225df5SJacob Faibussowitsch   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
84834a1e0b3eSMatthew G. Knepley 
84844a1e0b3eSMatthew G. Knepley   Not collective
84854a1e0b3eSMatthew G. Knepley 
84864a1e0b3eSMatthew G. Knepley   Input Parameters:
8487a1cb98faSBarry Smith + dmRow            - The `DM` for the row fields
848820f4b53cSBarry Smith . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
8489e8e188d2SZach Atkins . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
849020f4b53cSBarry Smith . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
8491a1cb98faSBarry Smith . dmCol            - The `DM` for the column fields
849220f4b53cSBarry Smith . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
8493e8e188d2SZach Atkins . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
849420f4b53cSBarry Smith . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
84954a1e0b3eSMatthew G. Knepley . A                - The matrix
8496a1cb98faSBarry Smith . point            - The point in the `DM`
84974a1e0b3eSMatthew G. Knepley . values           - The array of values
8498a1cb98faSBarry Smith - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
84994a1e0b3eSMatthew G. Knepley 
85004a1e0b3eSMatthew G. Knepley   Level: intermediate
85014a1e0b3eSMatthew G. Knepley 
85021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
85034a1e0b3eSMatthew G. Knepley @*/
8504e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, PetscBool useRowPerm, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, PetscBool useColPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8505d71ae5a4SJacob Faibussowitsch {
850671f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
850771f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
8508c789d87fSToby Isaac   PetscInt           numIndicesRow = -1, numIndicesCol = -1;
85097caea556SToby Isaac   const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2;
8510c789d87fSToby Isaac 
851171f0bbf9SMatthew G. Knepley   PetscErrorCode ierr;
851271f0bbf9SMatthew G. Knepley 
851371f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
851471f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
85159566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
851671f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
85179566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
851871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
8519e8e188d2SZach Atkins   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5);
85209566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
8521e8e188d2SZach Atkins   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6);
85229566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
8523e8e188d2SZach Atkins   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7);
8524e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 9);
852571f0bbf9SMatthew G. Knepley 
8526c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow));
8527c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol));
85287caea556SToby Isaac   valuesV1 = valuesV0;
8529c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE));
85307caea556SToby Isaac   valuesV2 = valuesV1;
8531c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE));
853271f0bbf9SMatthew G. Knepley 
8533c789d87fSToby Isaac   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2));
8534d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8535c789d87fSToby Isaac   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode);
853671f0bbf9SMatthew G. Knepley   if (ierr) {
853771f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
853871f0bbf9SMatthew G. Knepley 
85399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
85409566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
85419566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
85427caea556SToby Isaac     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2));
85437caea556SToby Isaac     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
85447caea556SToby Isaac     if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
85457caea556SToby Isaac     if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
8546d3d1a6afSToby Isaac   }
854771f0bbf9SMatthew G. Knepley 
85487caea556SToby Isaac   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2));
85497caea556SToby Isaac   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
85507caea556SToby Isaac   if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
85517caea556SToby Isaac   if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
85523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8553552f7358SJed Brown }
8554552f7358SJed Brown 
8555d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8556d71ae5a4SJacob Faibussowitsch {
8557de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
8558de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8559de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
8560de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
856117c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8562de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
8563412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
85644ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8565de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
8566de41b84cSMatthew G. Knepley 
8567de41b84cSMatthew G. Knepley   PetscFunctionBegin;
8568de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8569de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
85709566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8571de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
85729566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8573de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
85749566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8575de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
85769566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8577de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8578de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
85799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
858063a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
85819566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
85829566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
8583de41b84cSMatthew G. Knepley   /* Column indices */
85849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
85854ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
8586de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
8587de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
85889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8589de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8590de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8591de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
8592de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
8593de41b84cSMatthew G. Knepley       ++q;
8594de41b84cSMatthew G. Knepley     }
8595de41b84cSMatthew G. Knepley   }
8596de41b84cSMatthew G. Knepley   numCPoints = q;
8597de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8598de41b84cSMatthew G. Knepley     PetscInt fdof;
8599de41b84cSMatthew G. Knepley 
86009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
86014ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8602de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
86039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8604de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
8605de41b84cSMatthew G. Knepley     }
8606de41b84cSMatthew G. Knepley     numCIndices += dof;
8607de41b84cSMatthew G. Knepley   }
8608de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8609de41b84cSMatthew G. Knepley   /* Row indices */
86109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8611412e9a14SMatthew G. Knepley   {
8612012bc364SMatthew G. Knepley     DMPlexTransform tr;
8613012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8614012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8615012bc364SMatthew G. Knepley 
86169566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
86179566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
86189566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8619012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
86209566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8621412e9a14SMatthew G. Knepley   }
86229566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8623de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
8624de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
86259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8626de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
86279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8628de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
8629de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
86309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
86314ca5e9f5SMatthew G. Knepley         if (!dof) continue;
86329371c9d4SSatish Balay         for (s = 0; s < q; ++s)
86339371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
86344ca5e9f5SMatthew G. Knepley         if (s < q) continue;
8635de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
8636de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8637de41b84cSMatthew G. Knepley         ++q;
8638de41b84cSMatthew G. Knepley       }
8639de41b84cSMatthew G. Knepley     }
86409566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8641de41b84cSMatthew G. Knepley   }
8642de41b84cSMatthew G. Knepley   numFPoints = q;
8643de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8644de41b84cSMatthew G. Knepley     PetscInt fdof;
8645de41b84cSMatthew G. Knepley 
86469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
86474ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8648de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
86499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8650de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
8651de41b84cSMatthew G. Knepley     }
8652de41b84cSMatthew G. Knepley     numFIndices += dof;
8653de41b84cSMatthew G. Knepley   }
8654de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8655de41b84cSMatthew G. Knepley 
86561dca8a05SBarry 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);
86571dca8a05SBarry 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);
86589566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
86599566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8660de41b84cSMatthew G. Knepley   if (numFields) {
86614acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
86624acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
86634acb8e1eSToby Isaac 
86644acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
86659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
86669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8667de41b84cSMatthew G. Knepley     }
86684acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
86699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
86709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
86714acb8e1eSToby Isaac     }
86724acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
86739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
86749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
86754acb8e1eSToby Isaac     }
86764acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
86779566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
86789566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8679de41b84cSMatthew G. Knepley     }
8680de41b84cSMatthew G. Knepley   } else {
86814acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
86824acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
86834acb8e1eSToby Isaac 
86849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
86859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
86864acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
86874acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
86884acb8e1eSToby Isaac 
86899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
86909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8691de41b84cSMatthew G. Knepley     }
86924acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
86934acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
86944acb8e1eSToby Isaac 
86959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
86969566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8697de41b84cSMatthew G. Knepley     }
86989566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
86999566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8700de41b84cSMatthew G. Knepley   }
87019566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
87024acb8e1eSToby Isaac   /* TODO: flips */
8703d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8704de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8705de41b84cSMatthew G. Knepley   if (ierr) {
8706de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8707de41b84cSMatthew G. Knepley 
87089566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
87099566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
87109566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
87119566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
87129566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8713de41b84cSMatthew G. Knepley   }
87149566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
87159566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
87169566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
87179566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
87183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8719de41b84cSMatthew G. Knepley }
8720de41b84cSMatthew G. Knepley 
8721d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8722d71ae5a4SJacob Faibussowitsch {
87237c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
87247c927364SMatthew G. Knepley   PetscInt       *cpoints      = NULL;
8725230af79eSStefano Zampini   PetscInt        foffsets[32] = {0}, coffsets[32] = {0};
872617c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8727412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
87287c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
87297c927364SMatthew G. Knepley 
87307c927364SMatthew G. Knepley   PetscFunctionBegin;
87317c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
87327c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
87339566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
87347c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
87359566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
87367c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
87379566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
87387c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
87399566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
87407c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
87419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
874263a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
87437c927364SMatthew G. Knepley   /* Column indices */
87449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
87457c927364SMatthew G. Knepley   maxFPoints = numCPoints;
87467c927364SMatthew G. Knepley   /* Compress out points not in the section */
87477c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
87489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
87497c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
87507c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
87517c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
87527c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
87537c927364SMatthew G. Knepley       ++q;
87547c927364SMatthew G. Knepley     }
87557c927364SMatthew G. Knepley   }
87567c927364SMatthew G. Knepley   numCPoints = q;
87577c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
87587c927364SMatthew G. Knepley     PetscInt fdof;
87597c927364SMatthew G. Knepley 
87609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
87617c927364SMatthew G. Knepley     if (!dof) continue;
87627c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
87639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
87647c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
87657c927364SMatthew G. Knepley     }
87667c927364SMatthew G. Knepley     numCIndices += dof;
87677c927364SMatthew G. Knepley   }
87687c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
87697c927364SMatthew G. Knepley   /* Row indices */
87709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8771412e9a14SMatthew G. Knepley   {
8772012bc364SMatthew G. Knepley     DMPlexTransform tr;
8773012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8774012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8775012bc364SMatthew G. Knepley 
87769566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
87779566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
87789566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8779012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
87809566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8781412e9a14SMatthew G. Knepley   }
87829566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
87837c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
87847c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
87859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
87867c927364SMatthew G. Knepley     /* Compress out points not in the section */
87879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
87887c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
87897c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
87909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
87917c927364SMatthew G. Knepley         if (!dof) continue;
87929371c9d4SSatish Balay         for (s = 0; s < q; ++s)
87939371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
87947c927364SMatthew G. Knepley         if (s < q) continue;
87957c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
87967c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
87977c927364SMatthew G. Knepley         ++q;
87987c927364SMatthew G. Knepley       }
87997c927364SMatthew G. Knepley     }
88009566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
88017c927364SMatthew G. Knepley   }
88027c927364SMatthew G. Knepley   numFPoints = q;
88037c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
88047c927364SMatthew G. Knepley     PetscInt fdof;
88057c927364SMatthew G. Knepley 
88069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
88077c927364SMatthew G. Knepley     if (!dof) continue;
88087c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
88099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
88107c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
88117c927364SMatthew G. Knepley     }
88127c927364SMatthew G. Knepley     numFIndices += dof;
88137c927364SMatthew G. Knepley   }
88147c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
88157c927364SMatthew G. Knepley 
88161dca8a05SBarry 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);
88171dca8a05SBarry 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);
88187c927364SMatthew G. Knepley   if (numFields) {
88194acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
88204acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
88214acb8e1eSToby Isaac 
88224acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
88239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
88249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
88257c927364SMatthew G. Knepley     }
88264acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
88279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
88289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
88294acb8e1eSToby Isaac     }
88304acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
88319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
88329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
88334acb8e1eSToby Isaac     }
88344acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
88359566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
88369566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
88377c927364SMatthew G. Knepley     }
88387c927364SMatthew G. Knepley   } else {
88394acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
88404acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
88414acb8e1eSToby Isaac 
88429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
88439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
88444acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
88454acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
88464acb8e1eSToby Isaac 
88479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
88489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
88497c927364SMatthew G. Knepley     }
88504acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
88514acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
88524acb8e1eSToby Isaac 
88539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
88549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
88557c927364SMatthew G. Knepley     }
88569566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
88579566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
88587c927364SMatthew G. Knepley   }
88599566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
88609566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
88613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
88627c927364SMatthew G. Knepley }
88637c927364SMatthew G. Knepley 
8864cc4c1da9SBarry Smith /*@
88657cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
88667cd05799SMatthew G. Knepley 
88677cd05799SMatthew G. Knepley   Input Parameter:
8868a1cb98faSBarry Smith . dm - The `DMPLEX` object
88697cd05799SMatthew G. Knepley 
88707cd05799SMatthew G. Knepley   Output Parameter:
88717cd05799SMatthew G. Knepley . cellHeight - The height of a cell
88727cd05799SMatthew G. Knepley 
88737cd05799SMatthew G. Knepley   Level: developer
88747cd05799SMatthew G. Knepley 
88751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
88767cd05799SMatthew G. Knepley @*/
8877d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8878d71ae5a4SJacob Faibussowitsch {
8879552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8880552f7358SJed Brown 
8881552f7358SJed Brown   PetscFunctionBegin;
8882552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88834f572ea9SToby Isaac   PetscAssertPointer(cellHeight, 2);
8884552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
88853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8886552f7358SJed Brown }
8887552f7358SJed Brown 
8888cc4c1da9SBarry Smith /*@
88897cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
88907cd05799SMatthew G. Knepley 
88917cd05799SMatthew G. Knepley   Input Parameters:
8892a1cb98faSBarry Smith + dm         - The `DMPLEX` object
88937cd05799SMatthew G. Knepley - cellHeight - The height of a cell
88947cd05799SMatthew G. Knepley 
88957cd05799SMatthew G. Knepley   Level: developer
88967cd05799SMatthew G. Knepley 
88971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
88987cd05799SMatthew G. Knepley @*/
8899d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8900d71ae5a4SJacob Faibussowitsch {
8901552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8902552f7358SJed Brown 
8903552f7358SJed Brown   PetscFunctionBegin;
8904552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8905552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
89063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8907552f7358SJed Brown }
8908552f7358SJed Brown 
8909e6139122SMatthew G. Knepley /*@
89102827ebadSStefano Zampini   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8911e6139122SMatthew G. Knepley 
89122827ebadSStefano Zampini   Input Parameters:
89132827ebadSStefano Zampini + dm - The `DMPLEX` object
89142827ebadSStefano Zampini - ct - The `DMPolytopeType` of the cell
8915e6139122SMatthew G. Knepley 
8916e6139122SMatthew G. Knepley   Output Parameters:
89172827ebadSStefano Zampini + start - The first cell of this type, or `NULL`
89182827ebadSStefano Zampini - end   - The upper bound on this celltype, or `NULL`
8919e6139122SMatthew G. Knepley 
89202a9f31c0SMatthew G. Knepley   Level: advanced
8921e6139122SMatthew G. Knepley 
89222827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8923e6139122SMatthew G. Knepley @*/
8924ce78bad3SBarry Smith PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end)
8925d71ae5a4SJacob Faibussowitsch {
89262827ebadSStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
89272827ebadSStefano Zampini   DMLabel  label;
89282827ebadSStefano Zampini   PetscInt pStart, pEnd;
8929e6139122SMatthew G. Knepley 
8930e6139122SMatthew G. Knepley   PetscFunctionBegin;
8931e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89322827ebadSStefano Zampini   if (start) {
89334f572ea9SToby Isaac     PetscAssertPointer(start, 3);
89342827ebadSStefano Zampini     *start = 0;
89352827ebadSStefano Zampini   }
89362827ebadSStefano Zampini   if (end) {
89374f572ea9SToby Isaac     PetscAssertPointer(end, 4);
89382827ebadSStefano Zampini     *end = 0;
89392827ebadSStefano Zampini   }
89402827ebadSStefano Zampini   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
89412827ebadSStefano Zampini   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
89422827ebadSStefano Zampini   if (mesh->tr) {
89432827ebadSStefano Zampini     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
89442827ebadSStefano Zampini   } else {
89452827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
89462827ebadSStefano Zampini     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
89472827ebadSStefano Zampini     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
89482827ebadSStefano Zampini   }
89493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8950e6139122SMatthew G. Knepley }
8951e6139122SMatthew G. Knepley 
895221c42226SMatthew G. Knepley /*@
895321c42226SMatthew G. Knepley   DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum
895421c42226SMatthew G. Knepley 
895521c42226SMatthew G. Knepley   Input Parameters:
895621c42226SMatthew G. Knepley + dm    - The `DMPLEX` object
895721c42226SMatthew G. Knepley - depth - The depth for the given point stratum
895821c42226SMatthew G. Knepley 
895921c42226SMatthew G. Knepley   Output Parameter:
896021c42226SMatthew G. Knepley . gsize - The global number of points in the stratum
896121c42226SMatthew G. Knepley 
896221c42226SMatthew G. Knepley   Level: advanced
896321c42226SMatthew G. Knepley 
896421c42226SMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
896521c42226SMatthew G. Knepley @*/
896621c42226SMatthew G. Knepley PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize)
896721c42226SMatthew G. Knepley {
896821c42226SMatthew G. Knepley   PetscSF         sf;
896921c42226SMatthew G. Knepley   const PetscInt *leaves;
897021c42226SMatthew G. Knepley   PetscInt        Nl, loc, start, end, lsize = 0;
897121c42226SMatthew G. Knepley 
897221c42226SMatthew G. Knepley   PetscFunctionBegin;
897321c42226SMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
897421c42226SMatthew G. Knepley   PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
897521c42226SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end));
897621c42226SMatthew G. Knepley   for (PetscInt p = start; p < end; ++p) {
897721c42226SMatthew G. Knepley     PetscCall(PetscFindInt(p, Nl, leaves, &loc));
897821c42226SMatthew G. Knepley     if (loc < 0) ++lsize;
897921c42226SMatthew G. Knepley   }
8980458b0db5SMartin Diehl   PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
898121c42226SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
898221c42226SMatthew G. Knepley }
898321c42226SMatthew G. Knepley 
8984d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8985d71ae5a4SJacob Faibussowitsch {
8986552f7358SJed Brown   PetscSection section, globalSection;
8987552f7358SJed Brown   PetscInt    *numbers, p;
8988552f7358SJed Brown 
8989552f7358SJed Brown   PetscFunctionBegin;
8990d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
89919566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
89929566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
899348a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
89949566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8995eb9d3e4dSMatthew G. Knepley   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection));
89969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8997552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
89989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8999ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
9000ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
9001552f7358SJed Brown   }
90029566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
9003ef48cebcSMatthew G. Knepley   if (globalSize) {
9004ef48cebcSMatthew G. Knepley     PetscLayout layout;
90059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
90069566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
90079566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
9008ef48cebcSMatthew G. Knepley   }
90099566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
90109566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
90113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9012552f7358SJed Brown }
9013552f7358SJed Brown 
9014e2b8d0fcSMatthew G. Knepley /*@
9015e2b8d0fcSMatthew G. Knepley   DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process
9016e2b8d0fcSMatthew G. Knepley 
9017bc9da2b0SJose E. Roman   Input Parameters:
9018e2b8d0fcSMatthew G. Knepley + dm         - The `DMPLEX` object
9019e2b8d0fcSMatthew G. Knepley - includeAll - Whether to include all cells, or just the simplex and box cells
9020e2b8d0fcSMatthew G. Knepley 
9021e2b8d0fcSMatthew G. Knepley   Output Parameter:
9022e2b8d0fcSMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
9023e2b8d0fcSMatthew G. Knepley 
9024e2b8d0fcSMatthew G. Knepley   Level: developer
9025e2b8d0fcSMatthew G. Knepley 
9026e2b8d0fcSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`
9027e2b8d0fcSMatthew G. Knepley @*/
9028e2b8d0fcSMatthew G. Knepley PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers)
9029d71ae5a4SJacob Faibussowitsch {
9030412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
9031552f7358SJed Brown 
9032552f7358SJed Brown   PetscFunctionBegin;
90339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
9034e2b8d0fcSMatthew G. Knepley   if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
90359566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
90369566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
90373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9038552f7358SJed Brown }
903981ed3555SMatthew G. Knepley 
90408dab3259SMatthew G. Knepley /*@
90417cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
90427cd05799SMatthew G. Knepley 
90437cd05799SMatthew G. Knepley   Input Parameter:
9044a1cb98faSBarry Smith . dm - The `DMPLEX` object
90457cd05799SMatthew G. Knepley 
90467cd05799SMatthew G. Knepley   Output Parameter:
90477cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
90487cd05799SMatthew G. Knepley 
90497cd05799SMatthew G. Knepley   Level: developer
90507cd05799SMatthew G. Knepley 
9051e2b8d0fcSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()`
90527cd05799SMatthew G. Knepley @*/
9053d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9054d71ae5a4SJacob Faibussowitsch {
905581ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
905681ed3555SMatthew G. Knepley 
905781ed3555SMatthew G. Knepley   PetscFunctionBegin;
905881ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9059e2b8d0fcSMatthew G. Knepley   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers));
9060552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
90613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9062552f7358SJed Brown }
9063552f7358SJed Brown 
9064d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
9065d71ae5a4SJacob Faibussowitsch {
9066412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
906781ed3555SMatthew G. Knepley 
906881ed3555SMatthew G. Knepley   PetscFunctionBegin;
906981ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
90719566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
90723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
907381ed3555SMatthew G. Knepley }
907481ed3555SMatthew G. Knepley 
90758dab3259SMatthew G. Knepley /*@
90766aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
90777cd05799SMatthew G. Knepley 
90787cd05799SMatthew G. Knepley   Input Parameter:
9079a1cb98faSBarry Smith . dm - The `DMPLEX` object
90807cd05799SMatthew G. Knepley 
90817cd05799SMatthew G. Knepley   Output Parameter:
90827cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
90837cd05799SMatthew G. Knepley 
90847cd05799SMatthew G. Knepley   Level: developer
90857cd05799SMatthew G. Knepley 
90861cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
90877cd05799SMatthew G. Knepley @*/
9088d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9089d71ae5a4SJacob Faibussowitsch {
9090552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
9091552f7358SJed Brown 
9092552f7358SJed Brown   PetscFunctionBegin;
9093552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90949566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
9095552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
90963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9097552f7358SJed Brown }
9098552f7358SJed Brown 
90998dab3259SMatthew G. Knepley /*@
9100966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
9101966484cfSJed Brown 
910220f4b53cSBarry Smith   Collective
91037cd05799SMatthew G. Knepley 
91047cd05799SMatthew G. Knepley   Input Parameter:
9105a1cb98faSBarry Smith . dm - The `DMPLEX` object
91067cd05799SMatthew G. Knepley 
91077cd05799SMatthew G. Knepley   Output Parameter:
91087cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
91097cd05799SMatthew G. Knepley 
9110a1cb98faSBarry Smith   Level: developer
9111966484cfSJed Brown 
9112a1cb98faSBarry Smith   Notes:
9113a1cb98faSBarry Smith   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
9114966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
9115966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
9116966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
9117966484cfSJed Brown 
9118966484cfSJed Brown   The partitioned mesh is
9119966484cfSJed Brown   ```
9120966484cfSJed Brown   (2)--0--(3)--1--(4)    (1)--0--(2)
9121966484cfSJed Brown   ```
9122966484cfSJed Brown   and its global numbering is
9123966484cfSJed Brown   ```
9124966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
9125966484cfSJed Brown   ```
9126966484cfSJed Brown   Then the global numbering is provided as
9127966484cfSJed Brown   ```
9128966484cfSJed Brown   [0] Number of indices in set 5
9129966484cfSJed Brown   [0] 0 0
9130966484cfSJed Brown   [0] 1 1
9131966484cfSJed Brown   [0] 2 3
9132966484cfSJed Brown   [0] 3 4
9133966484cfSJed Brown   [0] 4 -6
9134966484cfSJed Brown   [1] Number of indices in set 3
9135966484cfSJed Brown   [1] 0 2
9136966484cfSJed Brown   [1] 1 5
9137966484cfSJed Brown   [1] 2 6
9138966484cfSJed Brown   ```
9139966484cfSJed Brown 
91401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
91417cd05799SMatthew G. Knepley @*/
9142d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
9143d71ae5a4SJacob Faibussowitsch {
9144ef48cebcSMatthew G. Knepley   IS        nums[4];
9145862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
9146ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
91470c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
9148ef48cebcSMatthew G. Knepley 
9149ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
9150ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
91520c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
91539566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
91540c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
9155862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
9156862913ffSStefano Zampini     PetscInt end;
9157862913ffSStefano Zampini 
9158862913ffSStefano Zampini     depths[d] = depth - d;
91599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
91600c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
9161862913ffSStefano Zampini   }
91620c15888dSMatthew G. Knepley   if (empty)
91630c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
91640c15888dSMatthew G. Knepley       depths[d] = -1;
91650c15888dSMatthew G. Knepley       starts[d] = -1;
91660c15888dSMatthew G. Knepley     }
91670c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
9168e91c04dfSPierre Jolivet   PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
9169ad540459SPierre Jolivet   for (d = 0; d <= depth; ++d) PetscCheck(starts[d] < 0 || depths[d] == gdepths[d], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT, depths[d], gdepths[d]);
91700c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
9171ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
9172ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
9173ef48cebcSMatthew G. Knepley 
91749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
91759566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
9176ef48cebcSMatthew G. Knepley     shift += gsize;
9177ef48cebcSMatthew G. Knepley   }
9178d1c35871SJed Brown   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
91799566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
91803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9181ef48cebcSMatthew G. Knepley }
9182ef48cebcSMatthew G. Knepley 
918308a22f4bSMatthew G. Knepley /*@
9184484edb7dSMatthew G. Knepley   DMPlexCreateEdgeNumbering - Create a global numbering for edges.
9185484edb7dSMatthew G. Knepley 
9186484edb7dSMatthew G. Knepley   Collective
9187484edb7dSMatthew G. Knepley 
9188484edb7dSMatthew G. Knepley   Input Parameter:
9189484edb7dSMatthew G. Knepley . dm - The `DMPLEX` object
9190484edb7dSMatthew G. Knepley 
9191484edb7dSMatthew G. Knepley   Output Parameter:
9192484edb7dSMatthew G. Knepley . globalEdgeNumbers - Global numbers for all edges on this process
9193484edb7dSMatthew G. Knepley 
9194484edb7dSMatthew G. Knepley   Level: developer
9195484edb7dSMatthew G. Knepley 
9196484edb7dSMatthew G. Knepley   Notes:
9197484edb7dSMatthew G. Knepley   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1).
9198484edb7dSMatthew G. Knepley 
9199484edb7dSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()`
9200484edb7dSMatthew G. Knepley @*/
9201484edb7dSMatthew G. Knepley PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers)
9202484edb7dSMatthew G. Knepley {
9203484edb7dSMatthew G. Knepley   PetscSF  sf;
9204484edb7dSMatthew G. Knepley   PetscInt eStart, eEnd;
9205484edb7dSMatthew G. Knepley 
9206484edb7dSMatthew G. Knepley   PetscFunctionBegin;
9207484edb7dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9208484edb7dSMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
9209484edb7dSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9210484edb7dSMatthew G. Knepley   PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers));
9211484edb7dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9212484edb7dSMatthew G. Knepley }
9213484edb7dSMatthew G. Knepley 
9214484edb7dSMatthew G. Knepley /*@
921508a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
921608a22f4bSMatthew G. Knepley 
921708a22f4bSMatthew G. Knepley   Input Parameter:
9218a1cb98faSBarry Smith . dm - The `DMPLEX` object
921908a22f4bSMatthew G. Knepley 
922008a22f4bSMatthew G. Knepley   Output Parameter:
922108a22f4bSMatthew G. Knepley . ranks - The rank field
922208a22f4bSMatthew G. Knepley 
9223a1cb98faSBarry Smith   Options Database Key:
922420f4b53cSBarry Smith . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
922508a22f4bSMatthew G. Knepley 
922608a22f4bSMatthew G. Knepley   Level: intermediate
922708a22f4bSMatthew G. Knepley 
92281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
922908a22f4bSMatthew G. Knepley @*/
9230d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
9231d71ae5a4SJacob Faibussowitsch {
923208a22f4bSMatthew G. Knepley   DM             rdm;
923308a22f4bSMatthew G. Knepley   PetscFE        fe;
923408a22f4bSMatthew G. Knepley   PetscScalar   *r;
923508a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
9236a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
923708a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
9238a55f9a55SMatthew G. Knepley   PetscBool      simplex;
923908a22f4bSMatthew G. Knepley 
924008a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
9241f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
92424f572ea9SToby Isaac   PetscAssertPointer(ranks, 2);
92439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
92449566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
92459566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
92469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
92479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9248a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
92499566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
92509566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
92519566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
92529566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
92539566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
92549566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
92559566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
92569566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
925708a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
925808a22f4bSMatthew G. Knepley     PetscScalar *lr;
925908a22f4bSMatthew G. Knepley 
92609566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
926171f09efeSPierre Jolivet     if (lr) *lr = rank;
926208a22f4bSMatthew G. Knepley   }
92639566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
92649566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
92653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
926608a22f4bSMatthew G. Knepley }
926708a22f4bSMatthew G. Knepley 
9268ca8062c8SMatthew G. Knepley /*@
9269acf3173eSStefano Zampini   DMPlexCreateLabelField - Create a field whose value is the label value for that point
927018e14f0cSMatthew G. Knepley 
927118e14f0cSMatthew G. Knepley   Input Parameters:
927220f4b53cSBarry Smith + dm    - The `DMPLEX`
927320f4b53cSBarry Smith - label - The `DMLabel`
927418e14f0cSMatthew G. Knepley 
927518e14f0cSMatthew G. Knepley   Output Parameter:
927618e14f0cSMatthew G. Knepley . val - The label value field
927718e14f0cSMatthew G. Knepley 
927820f4b53cSBarry Smith   Options Database Key:
927920f4b53cSBarry Smith . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
928018e14f0cSMatthew G. Knepley 
928118e14f0cSMatthew G. Knepley   Level: intermediate
928218e14f0cSMatthew G. Knepley 
92831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
928418e14f0cSMatthew G. Knepley @*/
9285d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
9286d71ae5a4SJacob Faibussowitsch {
92871033741fSStefano Zampini   DM             rdm, plex;
9288acf3173eSStefano Zampini   Vec            lval;
9289acf3173eSStefano Zampini   PetscSection   section;
929018e14f0cSMatthew G. Knepley   PetscFE        fe;
929118e14f0cSMatthew G. Knepley   PetscScalar   *v;
9292acf3173eSStefano Zampini   PetscInt       dim, pStart, pEnd, p, cStart;
9293acf3173eSStefano Zampini   DMPolytopeType ct;
9294acf3173eSStefano Zampini   char           name[PETSC_MAX_PATH_LEN];
9295acf3173eSStefano Zampini   const char    *lname, *prefix;
929618e14f0cSMatthew G. Knepley 
929718e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
929818e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
92994f572ea9SToby Isaac   PetscAssertPointer(label, 2);
93004f572ea9SToby Isaac   PetscAssertPointer(val, 3);
93019566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
9302acf3173eSStefano Zampini   PetscCall(DMConvert(rdm, DMPLEX, &plex));
9303acf3173eSStefano Zampini   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL));
9304acf3173eSStefano Zampini   PetscCall(DMPlexGetCellType(plex, cStart, &ct));
9305acf3173eSStefano Zampini   PetscCall(DMDestroy(&plex));
93069566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
9307acf3173eSStefano Zampini   PetscCall(DMGetOptionsPrefix(dm, &prefix));
9308acf3173eSStefano Zampini   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
9309acf3173eSStefano Zampini   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname));
9310acf3173eSStefano Zampini   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe));
9311acf3173eSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)fe, ""));
93129566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
93139566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
93149566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
93159566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
9316acf3173eSStefano Zampini   PetscCall(DMCreateLocalVector(rdm, &lval));
9317acf3173eSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)*val, lname));
9318acf3173eSStefano Zampini   PetscCall(DMGetLocalSection(rdm, &section));
9319acf3173eSStefano Zampini   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
9320acf3173eSStefano Zampini   PetscCall(VecGetArray(lval, &v));
9321acf3173eSStefano Zampini   for (p = pStart; p < pEnd; ++p) {
9322acf3173eSStefano Zampini     PetscInt cval, dof, off;
932318e14f0cSMatthew G. Knepley 
9324acf3173eSStefano Zampini     PetscCall(PetscSectionGetDof(section, p, &dof));
9325acf3173eSStefano Zampini     if (!dof) continue;
9326acf3173eSStefano Zampini     PetscCall(DMLabelGetValue(label, p, &cval));
9327acf3173eSStefano Zampini     PetscCall(PetscSectionGetOffset(section, p, &off));
9328acf3173eSStefano Zampini     for (PetscInt d = 0; d < dof; d++) v[off + d] = cval;
932918e14f0cSMatthew G. Knepley   }
9330acf3173eSStefano Zampini   PetscCall(VecRestoreArray(lval, &v));
9331acf3173eSStefano Zampini   PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val));
9332acf3173eSStefano Zampini   PetscCall(VecDestroy(&lval));
93339566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
93343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933518e14f0cSMatthew G. Knepley }
933618e14f0cSMatthew G. Knepley 
933718e14f0cSMatthew G. Knepley /*@
9338ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
9339ca8062c8SMatthew G. Knepley 
934069916449SMatthew G. Knepley   Input Parameter:
9341a1cb98faSBarry Smith . dm - The `DMPLEX` object
9342a1cb98faSBarry Smith 
9343a1cb98faSBarry Smith   Level: developer
9344ca8062c8SMatthew G. Knepley 
934595eb5ee5SVaclav Hapla   Notes:
934695eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
934795eb5ee5SVaclav Hapla 
934820f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9349ca8062c8SMatthew G. Knepley 
93501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9351ca8062c8SMatthew G. Knepley @*/
9352d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
9353d71ae5a4SJacob Faibussowitsch {
9354ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
9355ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
9356ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
935757beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
935857beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
9359ca8062c8SMatthew G. Knepley 
9360ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9361ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93629566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
93639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
93649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
9365ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
93669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9367ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
93689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
93699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
9370ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
937142e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
937242e66dfaSMatthew G. Knepley       PetscInt  d;
937342e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
93749371c9d4SSatish Balay         if (cone[c] == cone[d]) {
93759371c9d4SSatish Balay           dup = PETSC_TRUE;
93769371c9d4SSatish Balay           break;
93779371c9d4SSatish Balay         }
937842e66dfaSMatthew G. Knepley       }
93799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
93809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
9381ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
9382ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
9383ca8062c8SMatthew G. Knepley       }
938442e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
938563a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
938648a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
93879566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
938863a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
938948a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
93909566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
939163a3b9bcSJacob 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]);
9392f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
9393ca8062c8SMatthew G. Knepley       }
939442e66dfaSMatthew G. Knepley     }
93959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
93969371c9d4SSatish Balay     if (p != pp) {
93979371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
93989371c9d4SSatish Balay       continue;
93999371c9d4SSatish Balay     }
94009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
94019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
9402ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
94039566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
94049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
9405ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
94069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
94079371c9d4SSatish Balay         if (cone[c] != pp) {
94089371c9d4SSatish Balay           c = 0;
94099371c9d4SSatish Balay           break;
94109371c9d4SSatish Balay         }
9411ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
9412ca8062c8SMatthew G. Knepley       }
9413ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
941463a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
941548a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
94169566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
941763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
941848a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
94199566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
942063a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
9421ca8062c8SMatthew G. Knepley       }
9422ca8062c8SMatthew G. Knepley     }
9423ca8062c8SMatthew G. Knepley   }
942457beb4faSStefano Zampini   if (storagecheck) {
94259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
94269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
942763a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
942857beb4faSStefano Zampini   }
94293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9430ca8062c8SMatthew G. Knepley }
9431ca8062c8SMatthew G. Knepley 
9432412e9a14SMatthew G. Knepley /*
9433412e9a14SMatthew 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.
9434412e9a14SMatthew G. Knepley */
9435d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
9436d71ae5a4SJacob Faibussowitsch {
9437412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
9438412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
9439412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
9440412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
9441412e9a14SMatthew G. Knepley 
9442412e9a14SMatthew G. Knepley   PetscFunctionBegin;
9443412e9a14SMatthew G. Knepley   *unsplit = 0;
9444412e9a14SMatthew G. Knepley   switch (ct) {
9445d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
9446d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
9447d71ae5a4SJacob Faibussowitsch     break;
9448412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
94499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
94509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9451412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
94529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
9453412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
9454412e9a14SMatthew G. Knepley     }
9455412e9a14SMatthew G. Knepley     break;
9456412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
9457412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
94589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
94599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9460412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
94619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
94629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
9463412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
94649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
9465412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
9466412e9a14SMatthew G. Knepley           PetscInt p;
94679371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
94689371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
9469412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
9470412e9a14SMatthew G. Knepley         }
9471412e9a14SMatthew G. Knepley       }
9472412e9a14SMatthew G. Knepley     }
9473412e9a14SMatthew G. Knepley     break;
9474d71ae5a4SJacob Faibussowitsch   default:
9475d71ae5a4SJacob Faibussowitsch     break;
9476412e9a14SMatthew G. Knepley   }
9477412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
94789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
9479412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
9480412e9a14SMatthew G. Knepley   }
94813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9482412e9a14SMatthew G. Knepley }
9483412e9a14SMatthew G. Knepley 
9484ca8062c8SMatthew G. Knepley /*@
9485ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
9486ca8062c8SMatthew G. Knepley 
9487ca8062c8SMatthew G. Knepley   Input Parameters:
9488a1cb98faSBarry Smith + dm         - The `DMPLEX` object
948958723a97SMatthew G. Knepley - cellHeight - Normally 0
9490ca8062c8SMatthew G. Knepley 
9491a1cb98faSBarry Smith   Level: developer
9492a1cb98faSBarry Smith 
949395eb5ee5SVaclav Hapla   Notes:
949495eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
949525c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
9496ca8062c8SMatthew G. Knepley 
949720f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
949895eb5ee5SVaclav Hapla 
94991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9500ca8062c8SMatthew G. Knepley @*/
9501d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
9502d71ae5a4SJacob Faibussowitsch {
9503412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
9504412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
9505412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
9506ca8062c8SMatthew G. Knepley 
9507ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9508ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95099566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
95109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
95119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9512412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9513412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
9514412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
951558723a97SMatthew G. Knepley 
95169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9517412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
9518412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
95199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
952063a3b9bcSJacob 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));
9521412e9a14SMatthew G. Knepley     }
95229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
952358723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
952458723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
9525412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
952658723a97SMatthew G. Knepley     }
95279566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9528412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
9529412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
9530412e9a14SMatthew G. Knepley       PetscInt unsplit;
953142363296SMatthew G. Knepley 
95329566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9533412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
953442363296SMatthew G. Knepley     }
953563a3b9bcSJacob 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));
953642363296SMatthew G. Knepley   }
95373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9538ca8062c8SMatthew G. Knepley }
95399bf0dad6SMatthew G. Knepley 
95409bf0dad6SMatthew G. Knepley /*@
95419bf0dad6SMatthew 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
95429bf0dad6SMatthew G. Knepley 
954320f4b53cSBarry Smith   Collective
9544899ea2b8SJacob Faibussowitsch 
95459bf0dad6SMatthew G. Knepley   Input Parameters:
9546a1cb98faSBarry Smith + dm         - The `DMPLEX` object
95479bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
95489bf0dad6SMatthew G. Knepley 
9549a1cb98faSBarry Smith   Level: developer
9550a1cb98faSBarry Smith 
955145da879fSVaclav Hapla   Notes:
955245da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
955345da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
955445da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
955545da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
95569bf0dad6SMatthew G. Knepley 
9557a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
955895eb5ee5SVaclav Hapla 
95591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
95609bf0dad6SMatthew G. Knepley @*/
9561d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
9562d71ae5a4SJacob Faibussowitsch {
9563ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
9564899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
95659bf0dad6SMatthew G. Knepley 
95669bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
95679bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95688f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
95693ba16761SJacob Faibussowitsch   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
95708f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
95713ba16761SJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
95723ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
9573899ea2b8SJacob Faibussowitsch   }
9574899ea2b8SJacob Faibussowitsch 
95759566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
95769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
95779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9578ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
95799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
95803554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
9581412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
9582412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
9583ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
9584412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
9585412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
95869bf0dad6SMatthew G. Knepley 
95879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
95889566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9589412e9a14SMatthew G. Knepley       if (unsplit) continue;
95909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
95919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
95929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
95939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
95949bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
95959bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
95969bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
95979bf0dad6SMatthew G. Knepley       }
95989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
959963a3b9bcSJacob 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);
96009bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
9601d4961f80SStefano Zampini         DMPolytopeType fct;
96029bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
96039bf0dad6SMatthew G. Knepley 
96049566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
96059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
96069bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
96079bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
96089bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
96099bf0dad6SMatthew G. Knepley         }
961063a3b9bcSJacob 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]);
96119bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
9612b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
9613b5a892a1SMatthew G. Knepley             PetscInt v1;
9614b5a892a1SMatthew G. Knepley 
96159566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
961663a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
96179566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
961863a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
96199566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
962063a3b9bcSJacob 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]);
9621b5a892a1SMatthew G. Knepley           }
96229bf0dad6SMatthew G. Knepley         }
96239566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
9624412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
96259bf0dad6SMatthew G. Knepley       }
96269566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
96279566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
96289bf0dad6SMatthew G. Knepley     }
96293554e41dSMatthew G. Knepley   }
96303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9631552f7358SJed Brown }
96323913d7c8SMatthew G. Knepley 
9633bb6a34a8SMatthew G. Knepley /*@
9634bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
9635bb6a34a8SMatthew G. Knepley 
9636bb6a34a8SMatthew G. Knepley   Input Parameter:
9637a1cb98faSBarry Smith . dm - The `DMPLEX` object
9638a1cb98faSBarry Smith 
9639a1cb98faSBarry Smith   Level: developer
9640bb6a34a8SMatthew G. Knepley 
964195eb5ee5SVaclav Hapla   Notes:
964295eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
964395eb5ee5SVaclav Hapla 
964420f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9645bb6a34a8SMatthew G. Knepley 
96461cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9647bb6a34a8SMatthew G. Knepley @*/
9648d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
9649d71ae5a4SJacob Faibussowitsch {
9650a2a9e04cSMatthew G. Knepley   Vec       coordinates;
9651bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
9652bb6a34a8SMatthew G. Knepley   PetscReal vol;
965351a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9654bb6a34a8SMatthew G. Knepley 
9655bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
96569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
96579566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
96583ba16761SJacob Faibussowitsch   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
96599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
9660bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
96619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9662a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
96639566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
96643ba16761SJacob Faibussowitsch   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9665412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9666412e9a14SMatthew G. Knepley     DMPolytopeType ct;
9667412e9a14SMatthew G. Knepley     PetscInt       unsplit;
9668412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
9669412e9a14SMatthew G. Knepley 
96709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9671412e9a14SMatthew G. Knepley     switch (ct) {
9672412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9673412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9674d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9675d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
9676d71ae5a4SJacob Faibussowitsch       break;
9677d71ae5a4SJacob Faibussowitsch     default:
9678d71ae5a4SJacob Faibussowitsch       break;
9679412e9a14SMatthew G. Knepley     }
9680412e9a14SMatthew G. Knepley     switch (ct) {
9681412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
9682412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9683412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9684d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
9685d71ae5a4SJacob Faibussowitsch       continue;
9686d71ae5a4SJacob Faibussowitsch     default:
9687d71ae5a4SJacob Faibussowitsch       break;
9688412e9a14SMatthew G. Knepley     }
96899566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9690412e9a14SMatthew G. Knepley     if (unsplit) continue;
96919566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
96921dca8a05SBarry 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);
969363a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
96946858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
96956858538eSMatthew G. Knepley     if (depth > 1) {
96969566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
96971dca8a05SBarry 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);
969863a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9699bb6a34a8SMatthew G. Knepley     }
9700bb6a34a8SMatthew G. Knepley   }
97013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9702bb6a34a8SMatthew G. Knepley }
9703bb6a34a8SMatthew G. Knepley 
970403da9461SVaclav Hapla /*@
970520f4b53cSBarry Smith   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
97067726db96SVaclav Hapla 
970720f4b53cSBarry Smith   Collective
970803da9461SVaclav Hapla 
970903da9461SVaclav Hapla   Input Parameters:
9710a1cb98faSBarry Smith + dm              - The `DMPLEX` object
971120f4b53cSBarry Smith . pointSF         - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9712a1cb98faSBarry Smith - allowExtraRoots - Flag to allow extra points not present in the `DM`
9713a1cb98faSBarry Smith 
9714a1cb98faSBarry Smith   Level: developer
971503da9461SVaclav Hapla 
9716e83a0d2dSVaclav Hapla   Notes:
9717e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
971803da9461SVaclav Hapla 
9719a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
972095eb5ee5SVaclav Hapla 
9721baca6076SPierre Jolivet   Extra roots can come from periodic cuts, where additional points appear on the boundary
9722d7d32a9aSMatthew G. Knepley 
97231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
972403da9461SVaclav Hapla @*/
9725d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9726d71ae5a4SJacob Faibussowitsch {
97277726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
97287726db96SVaclav Hapla   const PetscInt    *locals;
97297726db96SVaclav Hapla   const PetscSFNode *remotes;
9730f0cfc026SVaclav Hapla   PetscBool          distributed;
97317726db96SVaclav Hapla   MPI_Comm           comm;
97327726db96SVaclav Hapla   PetscMPIInt        rank;
973303da9461SVaclav Hapla 
973403da9461SVaclav Hapla   PetscFunctionBegin;
973503da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
97367726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
97377726db96SVaclav Hapla   else pointSF = dm->sf;
97387726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
97397726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
97407726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
97417726db96SVaclav Hapla   {
97427726db96SVaclav Hapla     PetscMPIInt mpiFlag;
97437726db96SVaclav Hapla 
97447726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
97457726db96SVaclav 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);
97467726db96SVaclav Hapla   }
97477726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
97489566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
97497726db96SVaclav Hapla   if (!distributed) {
97507726db96SVaclav 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);
97513ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
97528918e3e2SVaclav Hapla   }
97537726db96SVaclav 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);
97547726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
975503da9461SVaclav Hapla 
97567726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
97577726db96SVaclav Hapla   {
97587726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
97597726db96SVaclav Hapla 
97607726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
97617726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9762d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
97637726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
97647726db96SVaclav Hapla   }
97657726db96SVaclav Hapla 
97667726db96SVaclav Hapla   /* Check there are no cells in interface */
97677726db96SVaclav Hapla   if (!overlap) {
97687726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
97697726db96SVaclav Hapla 
97709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
97719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9772f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
97737726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
9774f5869d18SMatthew G. Knepley 
97757726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
97767726db96SVaclav Hapla     }
977703da9461SVaclav Hapla   }
9778ece87651SVaclav Hapla 
97797726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
97807726db96SVaclav Hapla   {
97817726db96SVaclav Hapla     const PetscInt *rootdegree;
97827726db96SVaclav Hapla 
97837726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
97847726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9785f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
97867726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9787f5869d18SMatthew G. Knepley       const PetscInt *cone;
9788f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9789f5869d18SMatthew G. Knepley 
97909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
97919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9792f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9793f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
97947726db96SVaclav Hapla           if (locals) {
97959566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
97967726db96SVaclav Hapla           } else {
97977726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
97987726db96SVaclav Hapla           }
979963a3b9bcSJacob 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]);
9800f5869d18SMatthew G. Knepley         }
9801f5869d18SMatthew G. Knepley       }
9802ece87651SVaclav Hapla     }
98037726db96SVaclav Hapla   }
98043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
980503da9461SVaclav Hapla }
980603da9461SVaclav Hapla 
98077f9d8d6cSVaclav Hapla /*@
9808217fe35eSMatthew G. Knepley   DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices.
9809217fe35eSMatthew G. Knepley 
9810217fe35eSMatthew G. Knepley   Collective
9811217fe35eSMatthew G. Knepley 
9812217fe35eSMatthew G. Knepley   Input Parameter:
9813217fe35eSMatthew G. Knepley . dm - The `DMPLEX` object
9814217fe35eSMatthew G. Knepley 
9815217fe35eSMatthew G. Knepley   Level: developer
9816217fe35eSMatthew G. Knepley 
9817217fe35eSMatthew G. Knepley   Notes:
9818217fe35eSMatthew G. Knepley   This is mainly intended for debugging/testing purposes.
9819217fe35eSMatthew G. Knepley 
9820217fe35eSMatthew G. Knepley   Other cell types which are disconnected would be caught by the symmetry and face checks.
9821217fe35eSMatthew G. Knepley 
9822217fe35eSMatthew G. Knepley   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9823217fe35eSMatthew G. Knepley 
9824217fe35eSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()`
9825217fe35eSMatthew G. Knepley @*/
9826217fe35eSMatthew G. Knepley PetscErrorCode DMPlexCheckOrphanVertices(DM dm)
9827217fe35eSMatthew G. Knepley {
9828217fe35eSMatthew G. Knepley   PetscInt pStart, pEnd, vStart, vEnd;
9829217fe35eSMatthew G. Knepley 
9830217fe35eSMatthew G. Knepley   PetscFunctionBegin;
9831217fe35eSMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9832217fe35eSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9833217fe35eSMatthew G. Knepley   if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS);
9834217fe35eSMatthew G. Knepley   for (PetscInt v = vStart; v < vEnd; ++v) {
9835217fe35eSMatthew G. Knepley     PetscInt suppSize;
9836217fe35eSMatthew G. Knepley 
9837217fe35eSMatthew G. Knepley     PetscCall(DMPlexGetSupportSize(dm, v, &suppSize));
9838217fe35eSMatthew G. Knepley     PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v);
9839217fe35eSMatthew G. Knepley   }
9840217fe35eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9841217fe35eSMatthew G. Knepley }
9842217fe35eSMatthew G. Knepley 
9843217fe35eSMatthew G. Knepley /*@
984420f4b53cSBarry Smith   DMPlexCheck - Perform various checks of `DMPLEX` sanity
98457f9d8d6cSVaclav Hapla 
98467f9d8d6cSVaclav Hapla   Input Parameter:
9847a1cb98faSBarry Smith . dm - The `DMPLEX` object
9848a1cb98faSBarry Smith 
9849a1cb98faSBarry Smith   Level: developer
98507f9d8d6cSVaclav Hapla 
98517f9d8d6cSVaclav Hapla   Notes:
98527f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
98537f9d8d6cSVaclav Hapla 
985420f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
98557f9d8d6cSVaclav Hapla 
985620f4b53cSBarry Smith   Currently does not include `DMPlexCheckCellShape()`.
98577f9d8d6cSVaclav Hapla 
98581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
98597f9d8d6cSVaclav Hapla @*/
9860d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9861d71ae5a4SJacob Faibussowitsch {
98627f9d8d6cSVaclav Hapla   PetscInt cellHeight;
98637f9d8d6cSVaclav Hapla 
9864b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
98657f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
98669566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
98679566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
98689566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
98699566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9870d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
98719566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
9872217fe35eSMatthew G. Knepley   PetscCall(DMPlexCheckOrphanVertices(dm));
98733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9874b5a892a1SMatthew G. Knepley }
9875b5a892a1SMatthew G. Knepley 
98769371c9d4SSatish Balay typedef struct cell_stats {
9877068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9878068a5610SStefano Zampini   PetscInt  count;
9879068a5610SStefano Zampini } cell_stats_t;
9880068a5610SStefano Zampini 
9881d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9882d71ae5a4SJacob Faibussowitsch {
9883068a5610SStefano Zampini   PetscInt i, N = *len;
9884068a5610SStefano Zampini 
9885068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9886068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9887068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9888068a5610SStefano Zampini 
9889068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9890068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9891068a5610SStefano Zampini     B->sum += A->sum;
9892068a5610SStefano Zampini     B->squaresum += A->squaresum;
9893068a5610SStefano Zampini     B->count += A->count;
9894068a5610SStefano Zampini   }
9895068a5610SStefano Zampini }
9896068a5610SStefano Zampini 
9897068a5610SStefano Zampini /*@
989843fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9899068a5610SStefano Zampini 
990020f4b53cSBarry Smith   Collective
99018261a58bSMatthew G. Knepley 
9902068a5610SStefano Zampini   Input Parameters:
9903a1cb98faSBarry Smith + dm        - The `DMPLEX` object
990420f4b53cSBarry Smith . output    - If true, statistics will be displayed on `stdout`
9905a1cb98faSBarry Smith - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9906a1cb98faSBarry Smith 
9907a1cb98faSBarry Smith   Level: developer
9908068a5610SStefano Zampini 
990995eb5ee5SVaclav Hapla   Notes:
991095eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
991195eb5ee5SVaclav Hapla 
9912a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9913068a5610SStefano Zampini 
99141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9915068a5610SStefano Zampini @*/
9916d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9917d71ae5a4SJacob Faibussowitsch {
9918068a5610SStefano Zampini   DM           dmCoarse;
991943fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
992043fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
992143fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
992243fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9923412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
992443fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9925068a5610SStefano Zampini 
9926068a5610SStefano Zampini   PetscFunctionBegin;
9927068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9928068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9929068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9930068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9931068a5610SStefano Zampini   stats.count                 = 0;
9932068a5610SStefano Zampini 
99339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
99349566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
99359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
99369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
99379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
99389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9939412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9940068a5610SStefano Zampini     PetscInt  i;
9941068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9942068a5610SStefano Zampini 
99439566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
994463a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
994543fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9946068a5610SStefano Zampini       frobJ += J[i] * J[i];
9947068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9948068a5610SStefano Zampini     }
9949068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9950068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9951068a5610SStefano Zampini 
9952068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9953068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9954068a5610SStefano Zampini     stats.sum += cond;
9955068a5610SStefano Zampini     stats.squaresum += cond2;
9956068a5610SStefano Zampini     stats.count++;
99578261a58bSMatthew G. Knepley     if (output && cond > limit) {
995843fa8764SMatthew G. Knepley       PetscSection coordSection;
995943fa8764SMatthew G. Knepley       Vec          coordsLocal;
996043fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
996143fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
996243fa8764SMatthew G. Knepley 
99639566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
99649566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
99659566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
996663a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
996743fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
996863a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
996943fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
99709566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
99719566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
997243fa8764SMatthew G. Knepley         }
99739566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
997443fa8764SMatthew G. Knepley       }
99759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
997643fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
997743fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
997843fa8764SMatthew G. Knepley 
997943fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
998043fa8764SMatthew G. Knepley           PetscReal len;
998143fa8764SMatthew G. Knepley 
99829566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
998363a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
998443fa8764SMatthew G. Knepley         }
998543fa8764SMatthew G. Knepley       }
99869566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
99879566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
998843fa8764SMatthew G. Knepley     }
9989068a5610SStefano Zampini   }
99909566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9991068a5610SStefano Zampini 
9992068a5610SStefano Zampini   if (size > 1) {
9993068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9994068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9995068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9996068a5610SStefano Zampini     MPI_Op       statReduce;
9997068a5610SStefano Zampini 
99989566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
99999566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
100009566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
100019566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
100029566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
100039566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
10004068a5610SStefano Zampini   } else {
100059566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
10006068a5610SStefano Zampini   }
10007dd400576SPatrick Sanan   if (rank == 0) {
10008068a5610SStefano Zampini     count = globalStats.count;
10009068a5610SStefano Zampini     min   = globalStats.min;
10010068a5610SStefano Zampini     max   = globalStats.max;
10011068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
10012068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
10013068a5610SStefano Zampini   }
10014068a5610SStefano Zampini 
1001548a46eb9SPierre Jolivet   if (output) PetscCall(PetscPrintf(comm, "Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double)min, (double)max, (double)mean, (double)stdev));
100169566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
10017068a5610SStefano Zampini 
100189566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
10019068a5610SStefano Zampini   if (dmCoarse) {
10020068a5610SStefano Zampini     PetscBool isplex;
10021068a5610SStefano Zampini 
100229566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
100231baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
10024068a5610SStefano Zampini   }
100253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10026068a5610SStefano Zampini }
10027068a5610SStefano Zampini 
10028f108dbd7SJacob Faibussowitsch /*@
10029f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
10030f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
10031f108dbd7SJacob Faibussowitsch 
1003220f4b53cSBarry Smith   Collective
10033f108dbd7SJacob Faibussowitsch 
10034f108dbd7SJacob Faibussowitsch   Input Parameters:
10035a1cb98faSBarry Smith + dm   - The `DMPLEX` object
10036a1cb98faSBarry Smith . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
10037f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
10038f108dbd7SJacob Faibussowitsch 
10039f108dbd7SJacob Faibussowitsch   Output Parameters:
1004020f4b53cSBarry Smith + OrthQual      - `Vec` containing orthogonal quality per cell
10041a1cb98faSBarry Smith - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
10042f108dbd7SJacob Faibussowitsch 
10043f108dbd7SJacob Faibussowitsch   Options Database Keys:
10044a1cb98faSBarry Smith + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
10045f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view   - view OrthQual vector.
10046f108dbd7SJacob Faibussowitsch 
10047a1cb98faSBarry Smith   Level: intermediate
10048a1cb98faSBarry Smith 
10049f108dbd7SJacob Faibussowitsch   Notes:
10050a4e35b19SJacob Faibussowitsch   Orthogonal quality is given by the following formula\:
10051f108dbd7SJacob Faibussowitsch 
10052a1cb98faSBarry Smith   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
10053f108dbd7SJacob Faibussowitsch 
10054f108dbd7SJacob 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
10055f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
10056f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
10057f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
10058f108dbd7SJacob Faibussowitsch 
10059f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
10060f108dbd7SJacob Faibussowitsch 
10061a1cb98faSBarry Smith   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
10062f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
10063f108dbd7SJacob Faibussowitsch 
10064f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
10065f108dbd7SJacob Faibussowitsch 
100661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
10067f108dbd7SJacob Faibussowitsch @*/
10068ce78bad3SBarry Smith PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
10069d71ae5a4SJacob Faibussowitsch {
100706ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
100716ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
100726ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
10073f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
100746ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
10075f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
10076f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
10077f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
10078f108dbd7SJacob Faibussowitsch   IS                     glob;
10079f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
10080f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
10081f108dbd7SJacob Faibussowitsch 
10082f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
10083f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10084ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
100854f572ea9SToby Isaac   PetscAssertPointer(OrthQual, 4);
100866bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
100879566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
100889566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
1008963a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
100906ed19f2fSJacob Faibussowitsch   {
100916ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
100926ed19f2fSJacob Faibussowitsch 
100939566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
10094f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
10095f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
10096f108dbd7SJacob Faibussowitsch 
100979566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
1009898921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
10099f108dbd7SJacob Faibussowitsch     }
101006ed19f2fSJacob Faibussowitsch   }
10101f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
101024f572ea9SToby Isaac     PetscAssertPointer(OrthQualLabel, 5);
101039566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
101049566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
101059371c9d4SSatish Balay   } else {
101069371c9d4SSatish Balay     *OrthQualLabel = NULL;
101079371c9d4SSatish Balay   }
101089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
101099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
10110e2b8d0fcSMatthew G. Knepley   PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob));
101119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
101129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
101139566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
101149566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
101159566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
101169566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
101179566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
101189566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
101199566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
101209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
101219566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
101229566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
101239566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
101249566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
101259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
101266ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
101276ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
10128f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
10129f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
10130898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
10131f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
10132f108dbd7SJacob Faibussowitsch 
101336ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
10134f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
10135f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
101369566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
101379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
10138f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
101399566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
101406ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
101416ed19f2fSJacob Faibussowitsch       PetscInt         i;
101426ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
10143f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
10144f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
10145f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
10146f108dbd7SJacob Faibussowitsch 
10147f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
10148f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
101499566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
10150f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
101516ed19f2fSJacob Faibussowitsch       {
101526ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
101536ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
101546ed19f2fSJacob Faibussowitsch 
101559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
101569566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
101579566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
101586ed19f2fSJacob Faibussowitsch       }
10159f108dbd7SJacob Faibussowitsch 
10160f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
10161f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
10162f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
10163f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
10164f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
10165addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
10166addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
10167addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
10168f108dbd7SJacob Faibussowitsch       }
10169addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
10170addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
10171addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
10172f108dbd7SJacob Faibussowitsch 
10173f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
10174f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
10175f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
10176f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
10177f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
10178f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
10179f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
10180f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
10181f108dbd7SJacob Faibussowitsch       }
10182ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
10183ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
10184f108dbd7SJacob Faibussowitsch     }
101859566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
101869566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
10187f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
101886ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
10189f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
101909566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
10191f108dbd7SJacob Faibussowitsch     }
10192f108dbd7SJacob Faibussowitsch   }
101939566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
101949566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
101959566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
101969566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
101979566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
10198648c30bcSBarry Smith   PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
10199f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
102009566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
10201f108dbd7SJacob Faibussowitsch   }
102029566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
10203648c30bcSBarry Smith   PetscCall(PetscViewerDestroy(&vwr));
102049566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
102053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10206f108dbd7SJacob Faibussowitsch }
10207f108dbd7SJacob Faibussowitsch 
10208d5b43468SJose E. Roman /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
102091eb70e55SToby Isaac  * interpolator construction */
10210d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
10211d71ae5a4SJacob Faibussowitsch {
102121eb70e55SToby Isaac   PetscSection section, newSection, gsection;
102131eb70e55SToby Isaac   PetscSF      sf;
102141eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
102151eb70e55SToby Isaac 
102161eb70e55SToby Isaac   PetscFunctionBegin;
102171eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102184f572ea9SToby Isaac   PetscAssertPointer(odm, 2);
102199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
102209566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
102215440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
102221eb70e55SToby Isaac   if (!ghasConstraints) {
102239566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
102241eb70e55SToby Isaac     *odm = dm;
102253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
102261eb70e55SToby Isaac   }
102279566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
10228bb4b53efSMatthew G. Knepley   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm));
102299566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
102309566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
10231eb9d3e4dSMatthew G. Knepley   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection));
102329566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
102339566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
102343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102351eb70e55SToby Isaac }
102361eb70e55SToby Isaac 
10237d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
10238d71ae5a4SJacob Faibussowitsch {
102391eb70e55SToby Isaac   DM        dmco, dmfo;
102401eb70e55SToby Isaac   Mat       interpo;
102411eb70e55SToby Isaac   Vec       rscale;
102421eb70e55SToby Isaac   Vec       cglobalo, clocal;
102431eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
102441eb70e55SToby Isaac   PetscBool regular;
102451eb70e55SToby Isaac 
102461eb70e55SToby Isaac   PetscFunctionBegin;
102479566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
102489566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
102499566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
102509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
102519566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
102529566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
102539566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
102549566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
102559566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
102569566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
102579566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
102589566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
102599566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
102609566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
102619566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
102629566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
102639566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
102649566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
102659566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
102669566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
102679566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
102689566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
102699566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
102709566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
102711eb70e55SToby Isaac   *shift = fglobal;
102729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
102739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
102749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
102759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
102769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
102779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
102789566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
102799566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
102803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102811eb70e55SToby Isaac }
102821eb70e55SToby Isaac 
10283d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
10284d71ae5a4SJacob Faibussowitsch {
102851eb70e55SToby Isaac   PetscObject shifto;
102861eb70e55SToby Isaac   Vec         shift;
102871eb70e55SToby Isaac 
102881eb70e55SToby Isaac   PetscFunctionBegin;
102891eb70e55SToby Isaac   if (!interp) {
102901eb70e55SToby Isaac     Vec rscale;
102911eb70e55SToby Isaac 
102929566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
102939566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
102941eb70e55SToby Isaac   } else {
102959566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
102961eb70e55SToby Isaac   }
102979566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
102981eb70e55SToby Isaac   if (!shifto) {
102999566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
103009566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
103011eb70e55SToby Isaac     shifto = (PetscObject)shift;
103029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
103031eb70e55SToby Isaac   }
103041eb70e55SToby Isaac   shift = (Vec)shifto;
103059566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
103069566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
103079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
103083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103091eb70e55SToby Isaac }
103101eb70e55SToby Isaac 
10311bceba477SMatthew G. Knepley /* Pointwise interpolation
10312bceba477SMatthew G. Knepley      Just code FEM for now
10313bceba477SMatthew G. Knepley      u^f = I u^c
103144ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
103154ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
103164ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
10317bceba477SMatthew G. Knepley */
10318d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
10319d71ae5a4SJacob Faibussowitsch {
10320bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
10321bceba477SMatthew G. Knepley   PetscInt     m, n;
10322a063dac3SMatthew G. Knepley   void        *ctx;
1032368132eb9SMatthew G. Knepley   DM           cdm;
10324cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
10325bceba477SMatthew G. Knepley 
10326bceba477SMatthew G. Knepley   PetscFunctionBegin;
103279566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
103289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
103299566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
103309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
1033168132eb9SMatthew G. Knepley 
103329566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
103339566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
103349566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
103359566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
103369566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
1033768132eb9SMatthew G. Knepley 
103389566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
103399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
103409566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
103419566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
103429566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
103434db47ee9SStefano Zampini   if (scaling) {
103445d1c2e58SMatthew G. Knepley     /* Use naive scaling */
103459566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
103464db47ee9SStefano Zampini   }
103473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10348a063dac3SMatthew G. Knepley }
10349bceba477SMatthew G. Knepley 
10350d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
10351d71ae5a4SJacob Faibussowitsch {
103526dbf9973SLawrence Mitchell   VecScatter ctx;
1035390748bafSMatthew G. Knepley 
10354a063dac3SMatthew G. Knepley   PetscFunctionBegin;
103559566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
103569566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
103579566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
103583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10359bceba477SMatthew G. Knepley }
10360bceba477SMatthew G. Knepley 
10361d71ae5a4SJacob Faibussowitsch static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
10362d71ae5a4SJacob Faibussowitsch {
10363a102dd69SStefano Zampini   const PetscInt f  = (PetscInt)PetscRealPart(constants[numConstants]);
10364a102dd69SStefano Zampini   const PetscInt Nc = uOff[f + 1] - uOff[f];
10365a102dd69SStefano Zampini   for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
103663e9753d6SMatthew G. Knepley }
103673e9753d6SMatthew G. Knepley 
103681898fd5cSMatthew G. Knepley // The assumption here is that the test field is a vector and the basis field is a scalar (so we need the gradient)
103691898fd5cSMatthew G. Knepley static void g1_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
103701898fd5cSMatthew G. Knepley {
103711898fd5cSMatthew G. Knepley   for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0;
103721898fd5cSMatthew G. Knepley }
103731898fd5cSMatthew G. Knepley 
103748e9849d2SStefano Zampini PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass)
10375d71ae5a4SJacob Faibussowitsch {
10376b4937a87SMatthew G. Knepley   DM           dmc;
10377b4937a87SMatthew G. Knepley   PetscDS      ds;
10378b4937a87SMatthew G. Knepley   Vec          ones, locmass;
10379b4937a87SMatthew G. Knepley   IS           cellIS;
10380b4937a87SMatthew G. Knepley   PetscFormKey key;
10381b4937a87SMatthew G. Knepley   PetscInt     depth;
10382b4937a87SMatthew G. Knepley 
10383b4937a87SMatthew G. Knepley   PetscFunctionBegin;
103849566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
103859566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
103869566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
10387a102dd69SStefano Zampini   for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
103888e9849d2SStefano Zampini   if (mass) PetscCall(DMCreateGlobalVector(dm, mass));
103898e9849d2SStefano Zampini   if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass));
103908e9849d2SStefano Zampini   else PetscCall(DMGetLocalVector(dm, &locmass));
103918e9849d2SStefano Zampini   PetscCall(DMGetLocalVector(dm, &ones));
103928e9849d2SStefano Zampini   PetscCall(DMPlexGetDepth(dm, &depth));
103938e9849d2SStefano Zampini   PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS));
103949566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
103959566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
10396b4937a87SMatthew G. Knepley   key.label = NULL;
10397b4937a87SMatthew G. Knepley   key.value = 0;
10398b4937a87SMatthew G. Knepley   key.field = 0;
10399b4937a87SMatthew G. Knepley   key.part  = 0;
10400754e4fbaSMatthew G. Knepley   PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
104019566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
104028e9849d2SStefano Zampini   if (mass) {
104038e9849d2SStefano Zampini     PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass));
104048e9849d2SStefano Zampini     PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass));
104058e9849d2SStefano Zampini   }
104068e9849d2SStefano Zampini   PetscCall(DMRestoreLocalVector(dm, &ones));
104078e9849d2SStefano Zampini   if (lmass) *lmass = locmass;
104088e9849d2SStefano Zampini   else PetscCall(DMRestoreLocalVector(dm, &locmass));
104099566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
104103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10411b4937a87SMatthew G. Knepley }
10412b4937a87SMatthew G. Knepley 
10413d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
10414d71ae5a4SJacob Faibussowitsch {
10415bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
10416bd041c0cSMatthew G. Knepley   PetscInt     m, n;
10417bd041c0cSMatthew G. Knepley   void        *ctx;
10418bd041c0cSMatthew G. Knepley   DM           cdm;
10419bd041c0cSMatthew G. Knepley   PetscBool    regular;
10420bd041c0cSMatthew G. Knepley 
10421bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
104223e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
104233e9753d6SMatthew G. Knepley     DM            dmc;
104243e9753d6SMatthew G. Knepley     PetscDS       ds;
10425b4937a87SMatthew G. Knepley     PetscWeakForm wf;
104263e9753d6SMatthew G. Knepley     Vec           u;
104273e9753d6SMatthew G. Knepley     IS            cellIS;
1042806ad1575SMatthew G. Knepley     PetscFormKey  key;
104293e9753d6SMatthew G. Knepley     PetscInt      depth;
104303e9753d6SMatthew G. Knepley 
104319566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
104329566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
104339566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
104349566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
104359566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
10436a102dd69SStefano Zampini     for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
104379566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
104388d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
104399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
104409566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
104419566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
104426528b96dSMatthew G. Knepley     key.label = NULL;
104436528b96dSMatthew G. Knepley     key.value = 0;
104446528b96dSMatthew G. Knepley     key.field = 0;
1044506ad1575SMatthew G. Knepley     key.part  = 0;
10446754e4fbaSMatthew G. Knepley     PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
104479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
104488d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
104499566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
104503e9753d6SMatthew G. Knepley   } else {
104519566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
104529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
104539566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
104549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10455bd041c0cSMatthew G. Knepley 
104569566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
104579566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
104589566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
104599566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
10460bd041c0cSMatthew G. Knepley 
104619566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
104629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
104639566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
104649566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
104653e9753d6SMatthew G. Knepley   }
104669566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
104673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10468bd041c0cSMatthew G. Knepley }
10469bd041c0cSMatthew G. Knepley 
104701898fd5cSMatthew G. Knepley PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv)
104711898fd5cSMatthew G. Knepley {
104721898fd5cSMatthew G. Knepley   PetscSection gsc, gsf;
104731898fd5cSMatthew G. Knepley   PetscInt     m, n;
104741898fd5cSMatthew G. Knepley   void        *ctx;
104751898fd5cSMatthew G. Knepley 
104761898fd5cSMatthew G. Knepley   PetscFunctionBegin;
104771898fd5cSMatthew G. Knepley   PetscCall(DMGetGlobalSection(dmr, &gsf));
104781898fd5cSMatthew G. Knepley   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
104791898fd5cSMatthew G. Knepley   PetscCall(DMGetGlobalSection(dmc, &gsc));
104801898fd5cSMatthew G. Knepley   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
104811898fd5cSMatthew G. Knepley 
104821898fd5cSMatthew G. Knepley   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv));
104831898fd5cSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix"));
104841898fd5cSMatthew G. Knepley   PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
104851898fd5cSMatthew G. Knepley   PetscCall(MatSetType(*derv, dmc->mattype));
104861898fd5cSMatthew G. Knepley 
104871898fd5cSMatthew G. Knepley   PetscCall(DMGetApplicationContext(dmr, &ctx));
104881898fd5cSMatthew G. Knepley   {
104891898fd5cSMatthew G. Knepley     DM            ndmr;
104901898fd5cSMatthew G. Knepley     PetscDS       ds;
104911898fd5cSMatthew G. Knepley     PetscWeakForm wf;
104921898fd5cSMatthew G. Knepley     Vec           u;
104931898fd5cSMatthew G. Knepley     IS            cellIS;
104941898fd5cSMatthew G. Knepley     PetscFormKey  key;
104951898fd5cSMatthew G. Knepley     PetscInt      depth, Nf;
104961898fd5cSMatthew G. Knepley 
104971898fd5cSMatthew G. Knepley     PetscCall(DMClone(dmr, &ndmr));
104981898fd5cSMatthew G. Knepley     PetscCall(DMCopyDisc(dmr, ndmr));
104991898fd5cSMatthew G. Knepley     PetscCall(DMGetDS(ndmr, &ds));
105001898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetWeakForm(ds, &wf));
105011898fd5cSMatthew G. Knepley     PetscCall(PetscWeakFormClear(wf));
105021898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetNumFields(ds, &Nf));
105031898fd5cSMatthew G. Knepley     for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL));
105041898fd5cSMatthew G. Knepley     PetscCall(DMGetLocalVector(ndmr, &u));
105051898fd5cSMatthew G. Knepley     PetscCall(DMPlexGetDepth(ndmr, &depth));
105061898fd5cSMatthew G. Knepley     PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS));
105071898fd5cSMatthew G. Knepley     PetscCall(MatZeroEntries(*derv));
105081898fd5cSMatthew G. Knepley     key.label = NULL;
105091898fd5cSMatthew G. Knepley     key.value = 0;
105101898fd5cSMatthew G. Knepley     key.field = 0;
105111898fd5cSMatthew G. Knepley     key.part  = 0;
105121898fd5cSMatthew G. Knepley     PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL));
105131898fd5cSMatthew G. Knepley     PetscCall(ISDestroy(&cellIS));
105141898fd5cSMatthew G. Knepley     PetscCall(DMRestoreLocalVector(ndmr, &u));
105151898fd5cSMatthew G. Knepley     PetscCall(DMDestroy(&ndmr));
105161898fd5cSMatthew G. Knepley   }
105171898fd5cSMatthew G. Knepley   PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view"));
105181898fd5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
105191898fd5cSMatthew G. Knepley }
105201898fd5cSMatthew G. Knepley 
105210aef6b92SMatthew G. Knepley /*@
105220aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
105230aef6b92SMatthew G. Knepley 
105240aef6b92SMatthew G. Knepley   Input Parameter:
10525a1cb98faSBarry Smith . dm - The `DMPLEX` object
105260aef6b92SMatthew G. Knepley 
105270aef6b92SMatthew G. Knepley   Output Parameter:
105280aef6b92SMatthew G. Knepley . regular - The flag
105290aef6b92SMatthew G. Knepley 
105300aef6b92SMatthew G. Knepley   Level: intermediate
105310aef6b92SMatthew G. Knepley 
105321cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
105330aef6b92SMatthew G. Knepley @*/
10534d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
10535d71ae5a4SJacob Faibussowitsch {
105360aef6b92SMatthew G. Knepley   PetscFunctionBegin;
105370aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105384f572ea9SToby Isaac   PetscAssertPointer(regular, 2);
105390aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
105403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105410aef6b92SMatthew G. Knepley }
105420aef6b92SMatthew G. Knepley 
105430aef6b92SMatthew G. Knepley /*@
105440aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
105450aef6b92SMatthew G. Knepley 
105460aef6b92SMatthew G. Knepley   Input Parameters:
10547a1cb98faSBarry Smith + dm      - The `DMPLEX` object
105480aef6b92SMatthew G. Knepley - regular - The flag
105490aef6b92SMatthew G. Knepley 
105500aef6b92SMatthew G. Knepley   Level: intermediate
105510aef6b92SMatthew G. Knepley 
105521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
105530aef6b92SMatthew G. Knepley @*/
10554d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
10555d71ae5a4SJacob Faibussowitsch {
105560aef6b92SMatthew G. Knepley   PetscFunctionBegin;
105570aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105580aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
105593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105600aef6b92SMatthew G. Knepley }
105610aef6b92SMatthew G. Knepley 
10562a68b90caSToby Isaac /*@
10563f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
10564a1cb98faSBarry Smith   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
10565a68b90caSToby Isaac 
10566a1cb98faSBarry Smith   Not Collective
10567a68b90caSToby Isaac 
10568f899ff85SJose E. Roman   Input Parameter:
10569a1cb98faSBarry Smith . dm - The `DMPLEX` object
10570a68b90caSToby Isaac 
10571a68b90caSToby Isaac   Output Parameters:
1057220f4b53cSBarry Smith + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
1057320f4b53cSBarry Smith - anchorIS      - If not `NULL`, set to the list of anchors indexed by `anchorSection`
10574a68b90caSToby Isaac 
10575a68b90caSToby Isaac   Level: intermediate
10576a68b90caSToby Isaac 
105771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
10578a68b90caSToby Isaac @*/
10579ce78bad3SBarry Smith PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS)
10580d71ae5a4SJacob Faibussowitsch {
10581a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
10582a68b90caSToby Isaac 
10583a68b90caSToby Isaac   PetscFunctionBegin;
10584a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105859566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
10586a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
10587a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
105883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10589a68b90caSToby Isaac }
10590a68b90caSToby Isaac 
10591a68b90caSToby Isaac /*@
10592a4e35b19SJacob Faibussowitsch   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.
10593a68b90caSToby Isaac 
1059420f4b53cSBarry Smith   Collective
10595a68b90caSToby Isaac 
10596a68b90caSToby Isaac   Input Parameters:
10597a1cb98faSBarry Smith + dm            - The `DMPLEX` object
10598a1cb98faSBarry Smith . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
10599a1cb98faSBarry Smith                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10600a1cb98faSBarry Smith - anchorIS      - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10601a68b90caSToby Isaac 
10602a68b90caSToby Isaac   Level: intermediate
10603a68b90caSToby Isaac 
10604a1cb98faSBarry Smith   Notes:
10605a4e35b19SJacob Faibussowitsch   Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to
10606a4e35b19SJacob Faibussowitsch   an outside value, the anchor constraints set a point's degrees of freedom to be a linear
10607a4e35b19SJacob Faibussowitsch   combination of other points' degrees of freedom.
10608a4e35b19SJacob Faibussowitsch 
10609a1cb98faSBarry Smith   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
10610a1cb98faSBarry Smith   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
10611a1cb98faSBarry Smith 
1061220f4b53cSBarry Smith   The reference counts of `anchorSection` and `anchorIS` are incremented.
10613a1cb98faSBarry Smith 
106141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
10615a68b90caSToby Isaac @*/
10616d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
10617d71ae5a4SJacob Faibussowitsch {
10618a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
10619e228b242SToby Isaac   PetscMPIInt result;
10620a68b90caSToby Isaac 
10621a68b90caSToby Isaac   PetscFunctionBegin;
10622a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10623e228b242SToby Isaac   if (anchorSection) {
10624e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
106259566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
106261dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
10627e228b242SToby Isaac   }
10628e228b242SToby Isaac   if (anchorIS) {
10629e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
106309566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
106311dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
10632e228b242SToby Isaac   }
10633a68b90caSToby Isaac 
106349566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
106359566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
10636a68b90caSToby Isaac   plex->anchorSection = anchorSection;
10637a68b90caSToby Isaac 
106389566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
106399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
10640a68b90caSToby Isaac   plex->anchorIS = anchorIS;
10641a68b90caSToby Isaac 
10642cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
10643a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
10644a68b90caSToby Isaac     const PetscInt *anchors;
10645a68b90caSToby Isaac 
106469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
106479566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
106489566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
10649a68b90caSToby Isaac     for (a = 0; a < size; a++) {
10650a68b90caSToby Isaac       PetscInt p;
10651a68b90caSToby Isaac 
10652a68b90caSToby Isaac       p = anchors[a];
10653a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
10654a68b90caSToby Isaac         PetscInt dof;
10655a68b90caSToby Isaac 
106569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10657a68b90caSToby Isaac         if (dof) {
106589566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
1065963a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
10660a68b90caSToby Isaac         }
10661a68b90caSToby Isaac       }
10662a68b90caSToby Isaac     }
106639566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
10664a68b90caSToby Isaac   }
10665f7c74593SToby Isaac   /* reset the generic constraints */
106669566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
106673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10668a68b90caSToby Isaac }
10669a68b90caSToby Isaac 
10670d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
10671d71ae5a4SJacob Faibussowitsch {
10672f7c74593SToby Isaac   PetscSection anchorSection;
106736995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
10674a68b90caSToby Isaac 
10675a68b90caSToby Isaac   PetscFunctionBegin;
10676a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
106779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
106789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
106799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
106806995de1eSToby Isaac   if (numFields) {
10681719ab38cSToby Isaac     PetscInt f;
106829566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
10683719ab38cSToby Isaac 
10684719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
10685719ab38cSToby Isaac       PetscInt numComp;
10686719ab38cSToby Isaac 
106879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
106889566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
10689719ab38cSToby Isaac     }
106906995de1eSToby Isaac   }
106919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
106929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
106936995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
106946995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
106956995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
106969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
10697a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
106989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10699a68b90caSToby Isaac     if (dof) {
107009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
107019566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
10702a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
107039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
107049566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
10705a68b90caSToby Isaac       }
10706a68b90caSToby Isaac     }
10707a68b90caSToby Isaac   }
107089566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
107099566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
107103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10711a68b90caSToby Isaac }
10712a68b90caSToby Isaac 
10713d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
10714d71ae5a4SJacob Faibussowitsch {
10715f7c74593SToby Isaac   PetscSection    aSec;
10716ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
107170ac89760SToby Isaac   const PetscInt *anchors;
107180ac89760SToby Isaac   PetscInt        numFields, f;
1071966ad2231SToby Isaac   IS              aIS;
10720e19f7ee6SMark Adams   MatType         mtype;
10721e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
107220ac89760SToby Isaac 
107230ac89760SToby Isaac   PetscFunctionBegin;
107240ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
107259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
107269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
107279566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
107289566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
107299566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
107309566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
107319566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
107329566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
10733e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
10734e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
10735e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
107369566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
107379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
107389566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
107396995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
107409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
107419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
107429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
107430ac89760SToby Isaac   i[0] = 0;
107449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
107450ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
10746f19733c5SToby Isaac     PetscInt rDof, rOff, r;
10747f19733c5SToby Isaac 
107489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10749f19733c5SToby Isaac     if (!rDof) continue;
107509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
107510ac89760SToby Isaac     if (numFields) {
107520ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
107530ac89760SToby Isaac         annz = 0;
10754f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
10755f19733c5SToby Isaac           a = anchors[rOff + r];
10756ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
107579566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
107580ac89760SToby Isaac           annz += aDof;
107590ac89760SToby Isaac         }
107609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
107619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10762ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
107630ac89760SToby Isaac       }
107642f7452b8SBarry Smith     } else {
107650ac89760SToby Isaac       annz = 0;
107669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
107670ac89760SToby Isaac       for (q = 0; q < dof; q++) {
10768ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
10769ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
107709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
107710ac89760SToby Isaac         annz += aDof;
107720ac89760SToby Isaac       }
107739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
107749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10775ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
107760ac89760SToby Isaac     }
107770ac89760SToby Isaac   }
107780ac89760SToby Isaac   nnz = i[m];
107799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
107800ac89760SToby Isaac   offset = 0;
107810ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
107820ac89760SToby Isaac     if (numFields) {
107830ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
107849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
107850ac89760SToby Isaac         for (q = 0; q < dof; q++) {
107860ac89760SToby Isaac           PetscInt rDof, rOff, r;
107879566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
107889566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
107890ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
107900ac89760SToby Isaac             PetscInt s;
107910ac89760SToby Isaac 
107920ac89760SToby Isaac             a = anchors[rOff + r];
10793ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
107949566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
107959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10796ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
107970ac89760SToby Isaac           }
107980ac89760SToby Isaac         }
107990ac89760SToby Isaac       }
108002f7452b8SBarry Smith     } else {
108019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
108020ac89760SToby Isaac       for (q = 0; q < dof; q++) {
108030ac89760SToby Isaac         PetscInt rDof, rOff, r;
108049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
108059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
108060ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
108070ac89760SToby Isaac           PetscInt s;
108080ac89760SToby Isaac 
108090ac89760SToby Isaac           a = anchors[rOff + r];
10810ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
108119566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
108129566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10813ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
108140ac89760SToby Isaac         }
108150ac89760SToby Isaac       }
108160ac89760SToby Isaac     }
108170ac89760SToby Isaac   }
108189566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
108199566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
108209566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
108219566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
108223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
108230ac89760SToby Isaac }
108240ac89760SToby Isaac 
10825d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10826d71ae5a4SJacob Faibussowitsch {
10827f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
10828f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
1082966ad2231SToby Isaac   Mat          cMat;
1083066ad2231SToby Isaac 
1083166ad2231SToby Isaac   PetscFunctionBegin;
1083266ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
108339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
1083466ad2231SToby Isaac   if (anchorSection) {
1083544a7f3ddSMatthew G. Knepley     PetscInt Nf;
10836e228b242SToby Isaac 
108379566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
108389566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
108399566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
108409566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
108419566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
108429566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
108439566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
108449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
1084566ad2231SToby Isaac   }
108463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1084766ad2231SToby Isaac }
10848a93c429eSMatthew G. Knepley 
10849d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10850d71ae5a4SJacob Faibussowitsch {
10851a93c429eSMatthew G. Knepley   IS           subis;
10852a93c429eSMatthew G. Knepley   PetscSection section, subsection;
10853a93c429eSMatthew G. Knepley 
10854a93c429eSMatthew G. Knepley   PetscFunctionBegin;
108559566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1085628b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
1085728b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10858a93c429eSMatthew G. Knepley   /* Create subdomain */
1085971f1c950SStefano Zampini   PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, PetscObjectComm((PetscObject)dm), NULL, subdm));
10860a93c429eSMatthew G. Knepley   /* Create submodel */
108619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
108629566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
108639566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
108649566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
108659566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
10866a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
10867a93c429eSMatthew G. Knepley   if (is) {
10868a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
10869a93c429eSMatthew G. Knepley     IS              spIS;
10870a93c429eSMatthew G. Knepley     const PetscInt *spmap;
10871a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
10872a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10873a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10874a93c429eSMatthew G. Knepley 
108759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
108769566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
108779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
108789566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
108799566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
108809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10881a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10882a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10883a93c429eSMatthew G. Knepley 
108849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10885a93c429eSMatthew G. Knepley       if (gdof > 0) {
10886a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10887a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10888a93c429eSMatthew G. Knepley 
108899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
108909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10891a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10892a93c429eSMatthew G. Knepley         }
10893a93c429eSMatthew G. Knepley         subSize += pSubSize;
10894a93c429eSMatthew G. Knepley         if (pSubSize) {
10895a93c429eSMatthew G. Knepley           if (bs < 0) {
10896a93c429eSMatthew G. Knepley             bs = pSubSize;
10897a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10898a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10899a93c429eSMatthew G. Knepley             bs = 1;
10900a93c429eSMatthew G. Knepley           }
10901a93c429eSMatthew G. Knepley         }
10902a93c429eSMatthew G. Knepley       }
10903a93c429eSMatthew G. Knepley     }
10904a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
109051690c2aeSBarry Smith     bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
109069371c9d4SSatish Balay     bsLocal[1] = bs;
109079566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
109089371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
109099371c9d4SSatish Balay       bs = 1;
109109371c9d4SSatish Balay     } else {
109119371c9d4SSatish Balay       bs = bsMinMax[0];
109129371c9d4SSatish Balay     }
109139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10914a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10915a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10916a93c429eSMatthew G. Knepley 
109179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10918a93c429eSMatthew G. Knepley       if (gdof > 0) {
10919a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10920a93c429eSMatthew G. Knepley 
109219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10922a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10923a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10924a93c429eSMatthew G. Knepley 
10925a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10926a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
109279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
109289566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10929a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10930a93c429eSMatthew G. Knepley           }
109319566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
109329566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10933ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10934a93c429eSMatthew G. Knepley         }
10935a93c429eSMatthew G. Knepley       }
10936a93c429eSMatthew G. Knepley     }
109379566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
109389566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10939a93c429eSMatthew G. Knepley     if (bs > 1) {
10940a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10941a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10942a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10943a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
109449371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
109459371c9d4SSatish Balay             set = 0;
109469371c9d4SSatish Balay             break;
109479371c9d4SSatish Balay           }
10948a93c429eSMatthew G. Knepley         }
10949a93c429eSMatthew G. Knepley       }
109509566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10951a93c429eSMatthew G. Knepley     }
109524758e3ceSMatthew G. Knepley     // Attach nullspace
109534758e3ceSMatthew G. Knepley     if (dm->nullspaceConstructors) {
10954a93c429eSMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
10955a93c429eSMatthew G. Knepley         (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10956a93c429eSMatthew G. Knepley         if ((*subdm)->nullspaceConstructors[f]) break;
10957a93c429eSMatthew G. Knepley       }
10958a93c429eSMatthew G. Knepley       if (f < Nf) {
10959a93c429eSMatthew G. Knepley         MatNullSpace nullSpace;
109609566063dSJacob Faibussowitsch         PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
109616823f3c5SBlaise Bourdin 
109629566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
109639566063dSJacob Faibussowitsch         PetscCall(MatNullSpaceDestroy(&nullSpace));
10964a93c429eSMatthew G. Knepley       }
10965a93c429eSMatthew G. Knepley     }
109664758e3ceSMatthew G. Knepley   }
109673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10968a93c429eSMatthew G. Knepley }
10969c0f0dcc3SMatthew G. Knepley 
10970c0f0dcc3SMatthew G. Knepley /*@
10971c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10972c0f0dcc3SMatthew G. Knepley 
10973a1cb98faSBarry Smith   Input Parameters:
10974a1cb98faSBarry Smith + dm     - The `DM`
109752a8381b2SBarry Smith - unused - unused argument
10976a1cb98faSBarry Smith 
10977a1cb98faSBarry Smith   Options Database Key:
10978a1cb98faSBarry Smith . -dm_plex_monitor_throughput - Activate the monitor
10979c0f0dcc3SMatthew G. Knepley 
10980c0f0dcc3SMatthew G. Knepley   Level: developer
10981c0f0dcc3SMatthew G. Knepley 
109821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10983c0f0dcc3SMatthew G. Knepley @*/
109842a8381b2SBarry Smith PetscErrorCode DMPlexMonitorThroughput(DM dm, void *unused)
10985d71ae5a4SJacob Faibussowitsch {
10986b665b14eSToby Isaac   PetscLogHandler default_handler;
10987b665b14eSToby Isaac 
109882611ad71SToby Isaac   PetscFunctionBegin;
109892611ad71SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10990b665b14eSToby Isaac   PetscCall(PetscLogGetDefaultHandler(&default_handler));
10991b665b14eSToby Isaac   if (default_handler) {
10992c0f0dcc3SMatthew G. Knepley     PetscLogEvent      event;
10993c0f0dcc3SMatthew G. Knepley     PetscEventPerfInfo eventInfo;
10994835f2295SStefano Zampini     PetscLogDouble     cellRate, flopRate;
10995c0f0dcc3SMatthew G. Knepley     PetscInt           cStart, cEnd, Nf, N;
10996c0f0dcc3SMatthew G. Knepley     const char        *name;
10997c0f0dcc3SMatthew G. Knepley 
109989566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
109999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
110009566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
110019566063dSJacob Faibussowitsch     PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
11002b665b14eSToby Isaac     PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo));
11003c0f0dcc3SMatthew G. Knepley     N        = (cEnd - cStart) * Nf * eventInfo.count;
11004c0f0dcc3SMatthew G. Knepley     flopRate = eventInfo.flops / eventInfo.time;
11005c0f0dcc3SMatthew G. Knepley     cellRate = N / eventInfo.time;
11006835f2295SStefano Zampini     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, cellRate, flopRate / 1.e6));
110072611ad71SToby Isaac   } else {
11008b665b14eSToby Isaac     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off or the default log handler is not running. Reconfigure using --with-log and run with -log_view.");
110092611ad71SToby Isaac   }
110103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11011c0f0dcc3SMatthew G. Knepley }
11012