xref: /petsc/src/dm/impls/plex/plex.c (revision 7d8e5ce9f72ff760efa1461533bbb9449d232627)
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>
20436823f3c5SBlaise Bourdin   #include <petscviewerexodusii.h>
20441e50132fSMatthew G. Knepley #endif
20451e50132fSMatthew G. Knepley 
2046d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
2047d71ae5a4SJacob Faibussowitsch {
20489f196a02SMartin Diehl   PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython;
2049002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
2050552f7358SJed Brown 
2051552f7358SJed Brown   PetscFunctionBegin;
2052552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2053552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20549f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
20559566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
20569566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
20589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
20599566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
20605f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
206122d6dc08SStefano Zampini   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
20629f196a02SMartin Diehl   if (isascii) {
20638135c375SStefano Zampini     PetscViewerFormat format;
20649566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20651baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
20661baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
2067c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
2068c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
20699566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
2070c6ccd67eSMatthew G. Knepley #else
2071c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2072552f7358SJed Brown #endif
2073e412dcbdSMatthew G. Knepley   } else if (isvtk) {
20749566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
2075e412dcbdSMatthew G. Knepley   } else if (isdraw) {
2076e44f6aebSMatthew G. Knepley     DM hdm;
2077e44f6aebSMatthew G. Knepley 
2078e44f6aebSMatthew G. Knepley     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
2079e44f6aebSMatthew G. Knepley     PetscCall(DMPlexView_Draw(hdm, viewer));
2080e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&hdm));
20818135c375SStefano Zampini   } else if (isglvis) {
20829566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
20831e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
20841e50132fSMatthew G. Knepley   } else if (isexodus) {
20856823f3c5SBlaise Bourdin     /*
2086caff39ffSPierre Jolivet       ExodusII requires that all sets be part of exactly one cell set.
20876823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
2088da81f932SPierre Jolivet       with ID 1, containing all cells.
20896823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
20906823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
20916823f3c5SBlaise Bourdin     */
20926823f3c5SBlaise Bourdin     PetscInt numCS;
20939566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
20946823f3c5SBlaise Bourdin     if (!numCS) {
20951e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
20969566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
20979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
20989566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
20996823f3c5SBlaise Bourdin     }
21009566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
21011e50132fSMatthew G. Knepley #endif
21025f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
21035f34f2dcSJed Brown   } else if (iscgns) {
21045f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
21055f34f2dcSJed Brown #endif
210622d6dc08SStefano Zampini   } else if (ispython) {
210722d6dc08SStefano Zampini     PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm));
21081baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
2109cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
21109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
2111cb3ba0daSMatthew G. Knepley   if (flg) {
2112cb3ba0daSMatthew G. Knepley     Vec ranks;
21139566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
21149566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
21159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
2116cb3ba0daSMatthew G. Knepley   }
2117002a2709SMatthew G. Knepley   /* Optionally view a label */
21189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
2119002a2709SMatthew G. Knepley   if (flg) {
2120002a2709SMatthew G. Knepley     DMLabel label;
2121002a2709SMatthew G. Knepley     Vec     val;
2122002a2709SMatthew G. Knepley 
21239566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
212428b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
21259566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
21269566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
21279566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
2128002a2709SMatthew G. Knepley   }
21293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2130552f7358SJed Brown }
2131552f7358SJed Brown 
21327f96f51bSksagiyam /*@
2133a1cb98faSBarry Smith   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
21347f96f51bSksagiyam 
213520f4b53cSBarry Smith   Collective
21367f96f51bSksagiyam 
21377f96f51bSksagiyam   Input Parameters:
2138a1cb98faSBarry Smith + dm     - The `DM` whose topology is to be saved
2139a1cb98faSBarry Smith - viewer - The `PetscViewer` to save it in
21407f96f51bSksagiyam 
21417f96f51bSksagiyam   Level: advanced
21427f96f51bSksagiyam 
21431cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
21447f96f51bSksagiyam @*/
2145d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2146d71ae5a4SJacob Faibussowitsch {
21477f96f51bSksagiyam   PetscBool ishdf5;
21487f96f51bSksagiyam 
21497f96f51bSksagiyam   PetscFunctionBegin;
21507f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21517f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21539566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
21547f96f51bSksagiyam   if (ishdf5) {
21557f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
21567f96f51bSksagiyam     IS                globalPointNumbering;
2157966bd95aSPierre Jolivet     PetscViewerFormat format;
21587f96f51bSksagiyam 
2159966bd95aSPierre Jolivet     PetscCall(PetscViewerGetFormat(viewer, &format));
2160966bd95aSPierre 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]);
21619566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
21629566063dSJacob Faibussowitsch     PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
21639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&globalPointNumbering));
21647f96f51bSksagiyam #else
21657f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
21667f96f51bSksagiyam #endif
21677f96f51bSksagiyam   }
21689566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
21693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21707f96f51bSksagiyam }
21717f96f51bSksagiyam 
217277b8e257Sksagiyam /*@
2173a1cb98faSBarry Smith   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
217477b8e257Sksagiyam 
217520f4b53cSBarry Smith   Collective
217677b8e257Sksagiyam 
217777b8e257Sksagiyam   Input Parameters:
2178a1cb98faSBarry Smith + dm     - The `DM` whose coordinates are to be saved
2179a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
218077b8e257Sksagiyam 
218177b8e257Sksagiyam   Level: advanced
218277b8e257Sksagiyam 
21831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
218477b8e257Sksagiyam @*/
2185d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2186d71ae5a4SJacob Faibussowitsch {
218777b8e257Sksagiyam   PetscBool ishdf5;
218877b8e257Sksagiyam 
218977b8e257Sksagiyam   PetscFunctionBegin;
219077b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
219177b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21929566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21939566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
219477b8e257Sksagiyam   if (ishdf5) {
219577b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
219677b8e257Sksagiyam     PetscViewerFormat format;
2197966bd95aSPierre Jolivet 
21989566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2199966bd95aSPierre 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]);
22009566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
220177b8e257Sksagiyam #else
220277b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
220377b8e257Sksagiyam #endif
220477b8e257Sksagiyam   }
22059566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
22063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
220777b8e257Sksagiyam }
220877b8e257Sksagiyam 
2209bd6565f1Sksagiyam /*@
2210a1cb98faSBarry Smith   DMPlexLabelsView - Saves `DMPLEX` labels into a file
2211bd6565f1Sksagiyam 
221220f4b53cSBarry Smith   Collective
2213bd6565f1Sksagiyam 
2214bd6565f1Sksagiyam   Input Parameters:
2215a1cb98faSBarry Smith + dm     - The `DM` whose labels are to be saved
2216a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
2217bd6565f1Sksagiyam 
2218bd6565f1Sksagiyam   Level: advanced
2219bd6565f1Sksagiyam 
22201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2221bd6565f1Sksagiyam @*/
2222d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2223d71ae5a4SJacob Faibussowitsch {
2224bd6565f1Sksagiyam   PetscBool ishdf5;
2225bd6565f1Sksagiyam 
2226bd6565f1Sksagiyam   PetscFunctionBegin;
2227bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2228bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22309566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2231bd6565f1Sksagiyam   if (ishdf5) {
2232bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
2233bd6565f1Sksagiyam     IS                globalPointNumbering;
2234bd6565f1Sksagiyam     PetscViewerFormat format;
2235bd6565f1Sksagiyam 
22369566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2237966bd95aSPierre 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]);
22389566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
22399566063dSJacob Faibussowitsch     PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
22409566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&globalPointNumbering));
2241bd6565f1Sksagiyam #else
2242bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2243bd6565f1Sksagiyam #endif
2244bd6565f1Sksagiyam   }
22459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
22463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2247bd6565f1Sksagiyam }
2248bd6565f1Sksagiyam 
2249021affd3Sksagiyam /*@
2250a1cb98faSBarry Smith   DMPlexSectionView - Saves a section associated with a `DMPLEX`
2251021affd3Sksagiyam 
225220f4b53cSBarry Smith   Collective
2253021affd3Sksagiyam 
2254021affd3Sksagiyam   Input Parameters:
2255a1cb98faSBarry Smith + dm        - The `DM` that contains the topology on which the section to be saved is defined
2256a1cb98faSBarry Smith . viewer    - The `PetscViewer` for saving
22570318f8a0SStefano Zampini - sectiondm - The `DM` that contains the section to be saved, can be `NULL`
2258021affd3Sksagiyam 
2259021affd3Sksagiyam   Level: advanced
2260021affd3Sksagiyam 
2261021affd3Sksagiyam   Notes:
2262420bcc1bSBarry 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.
2263021affd3Sksagiyam 
22640318f8a0SStefano 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.
2265021affd3Sksagiyam 
22661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2267021affd3Sksagiyam @*/
2268d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2269d71ae5a4SJacob Faibussowitsch {
2270021affd3Sksagiyam   PetscBool ishdf5;
2271021affd3Sksagiyam 
2272021affd3Sksagiyam   PetscFunctionBegin;
2273021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2274021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22750318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
2276021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
22779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22789566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2279021affd3Sksagiyam   if (ishdf5) {
2280021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
22819566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2282021affd3Sksagiyam #else
2283021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2284021affd3Sksagiyam #endif
2285021affd3Sksagiyam   }
22869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
22873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2288021affd3Sksagiyam }
2289021affd3Sksagiyam 
22903e97647fSksagiyam /*@
22913e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
22923e97647fSksagiyam 
229320f4b53cSBarry Smith   Collective
22943e97647fSksagiyam 
22953e97647fSksagiyam   Input Parameters:
2296a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2297a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
22980318f8a0SStefano Zampini . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
22993e97647fSksagiyam - vec       - The global vector to be saved
23003e97647fSksagiyam 
23013e97647fSksagiyam   Level: advanced
23023e97647fSksagiyam 
23033e97647fSksagiyam   Notes:
23040318f8a0SStefano 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.
23053e97647fSksagiyam 
230660225df5SJacob Faibussowitsch   Calling sequence:
2307a1cb98faSBarry Smith .vb
2308a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2309a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2310a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2311a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2312a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2313a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2314a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2315a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2316a1cb98faSBarry Smith        PetscSectionSetUp(section);
2317a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2318a1cb98faSBarry Smith        PetscSectionDestroy(&section);
2319a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2320a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2321a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2322a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2323a1cb98faSBarry Smith        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2324a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2325a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2326a1cb98faSBarry Smith        DMDestroy(&dm);
2327a1cb98faSBarry Smith .ve
23283e97647fSksagiyam 
23291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
23303e97647fSksagiyam @*/
2331d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2332d71ae5a4SJacob Faibussowitsch {
23333e97647fSksagiyam   PetscBool ishdf5;
23343e97647fSksagiyam 
23353e97647fSksagiyam   PetscFunctionBegin;
23363e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23373e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23380318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
23393e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
23403e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
23413e97647fSksagiyam   /* Check consistency */
23423e97647fSksagiyam   {
23433e97647fSksagiyam     PetscSection section;
23443e97647fSksagiyam     PetscBool    includesConstraints;
23453e97647fSksagiyam     PetscInt     m, m1;
23463e97647fSksagiyam 
23479566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
23489566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
23499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
23509566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
23519566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
235263a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
23533e97647fSksagiyam   }
23549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23559566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
23563e97647fSksagiyam   if (ishdf5) {
23573e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
23589566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
23593e97647fSksagiyam #else
23603e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23613e97647fSksagiyam #endif
23623e97647fSksagiyam   }
23639566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
23643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23653e97647fSksagiyam }
23663e97647fSksagiyam 
23673e97647fSksagiyam /*@
23683e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
23693e97647fSksagiyam 
237020f4b53cSBarry Smith   Collective
23713e97647fSksagiyam 
23723e97647fSksagiyam   Input Parameters:
2373a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2374a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
23750318f8a0SStefano Zampini . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL`
23763e97647fSksagiyam - vec       - The local vector to be saved
23773e97647fSksagiyam 
23783e97647fSksagiyam   Level: advanced
23793e97647fSksagiyam 
2380a1cb98faSBarry Smith   Note:
23810318f8a0SStefano 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.
23823e97647fSksagiyam 
238360225df5SJacob Faibussowitsch   Calling sequence:
2384a1cb98faSBarry Smith .vb
2385a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2386a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2387a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2388a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2389a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2390a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2391a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2392a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2393a1cb98faSBarry Smith        PetscSectionSetUp(section);
2394a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2395a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2396a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2397a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2398a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2399a1cb98faSBarry Smith        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2400a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2401a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2402a1cb98faSBarry Smith        DMDestroy(&dm);
2403a1cb98faSBarry Smith .ve
24043e97647fSksagiyam 
24051cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
24063e97647fSksagiyam @*/
2407d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2408d71ae5a4SJacob Faibussowitsch {
24093e97647fSksagiyam   PetscBool ishdf5;
24103e97647fSksagiyam 
24113e97647fSksagiyam   PetscFunctionBegin;
24123e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24133e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24140318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
24153e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
24163e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
24173e97647fSksagiyam   /* Check consistency */
24183e97647fSksagiyam   {
24193e97647fSksagiyam     PetscSection section;
24203e97647fSksagiyam     PetscBool    includesConstraints;
24213e97647fSksagiyam     PetscInt     m, m1;
24223e97647fSksagiyam 
24239566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
24249566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
24259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
24269566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
24279566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
242863a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
24293e97647fSksagiyam   }
24309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
24323e97647fSksagiyam   if (ishdf5) {
24333e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
24349566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
24353e97647fSksagiyam #else
24363e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24373e97647fSksagiyam #endif
24383e97647fSksagiyam   }
24399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
24403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24413e97647fSksagiyam }
24423e97647fSksagiyam 
2443d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2444d71ae5a4SJacob Faibussowitsch {
2445d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
24462c40f234SMatthew G. Knepley 
24472c40f234SMatthew G. Knepley   PetscFunctionBegin;
24482c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24492c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2451d4f5a9a0SVaclav Hapla   if (ishdf5) {
24522c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
24539c48423bSVaclav Hapla     PetscViewerFormat format;
24549566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
24559c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
24569566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2457509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24589566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
245998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
24603ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
24612c40f234SMatthew G. Knepley #else
24622c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2463552f7358SJed Brown #endif
246498921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2465552f7358SJed Brown }
2466552f7358SJed Brown 
2467ea8e1828Sksagiyam /*@
2468a1cb98faSBarry Smith   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2469ea8e1828Sksagiyam 
247020f4b53cSBarry Smith   Collective
2471ea8e1828Sksagiyam 
2472ea8e1828Sksagiyam   Input Parameters:
2473a1cb98faSBarry Smith + dm     - The `DM` into which the topology is loaded
2474a1cb98faSBarry Smith - viewer - The `PetscViewer` for the saved topology
2475ea8e1828Sksagiyam 
24762fe279fdSBarry Smith   Output Parameter:
24772c9a7b26SBarry 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;
24782c9a7b26SBarry Smith   `NULL` if unneeded
2479dec9e869Sksagiyam 
2480ea8e1828Sksagiyam   Level: advanced
2481ea8e1828Sksagiyam 
24821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2483a1cb98faSBarry Smith           `PetscViewer`, `PetscSF`
2484ea8e1828Sksagiyam @*/
2485d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2486d71ae5a4SJacob Faibussowitsch {
2487ea8e1828Sksagiyam   PetscBool ishdf5;
2488ea8e1828Sksagiyam 
2489ea8e1828Sksagiyam   PetscFunctionBegin;
2490ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2491ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24924f572ea9SToby Isaac   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
24939566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24949566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2495ea8e1828Sksagiyam   if (ishdf5) {
2496ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2497ea8e1828Sksagiyam     PetscViewerFormat format;
2498966bd95aSPierre Jolivet 
24999566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2500966bd95aSPierre 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]);
25019566063dSJacob Faibussowitsch     PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2502ea8e1828Sksagiyam #else
2503ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2504ea8e1828Sksagiyam #endif
2505ea8e1828Sksagiyam   }
25069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
25073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2508ea8e1828Sksagiyam }
2509ea8e1828Sksagiyam 
25103e701f1cSksagiyam /*@
2511a1cb98faSBarry Smith   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
25123e701f1cSksagiyam 
251320f4b53cSBarry Smith   Collective
25143e701f1cSksagiyam 
25153e701f1cSksagiyam   Input Parameters:
2516a1cb98faSBarry Smith + dm                   - The `DM` into which the coordinates are loaded
2517a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved coordinates
2518a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
25193e701f1cSksagiyam 
25203e701f1cSksagiyam   Level: advanced
25213e701f1cSksagiyam 
25221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2523a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
25243e701f1cSksagiyam @*/
2525d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2526d71ae5a4SJacob Faibussowitsch {
25273e701f1cSksagiyam   PetscBool ishdf5;
25283e701f1cSksagiyam 
25293e701f1cSksagiyam   PetscFunctionBegin;
25303e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25313e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2532c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
25339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
25353e701f1cSksagiyam   if (ishdf5) {
25363e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
25373e701f1cSksagiyam     PetscViewerFormat format;
2538966bd95aSPierre Jolivet 
25399566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2540966bd95aSPierre 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]);
25419566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
25423e701f1cSksagiyam #else
25433e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
25443e701f1cSksagiyam #endif
25453e701f1cSksagiyam   }
25469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
25473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25483e701f1cSksagiyam }
25493e701f1cSksagiyam 
2550b08ad5deSksagiyam /*@
2551a1cb98faSBarry Smith   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2552b08ad5deSksagiyam 
255320f4b53cSBarry Smith   Collective
2554b08ad5deSksagiyam 
2555b08ad5deSksagiyam   Input Parameters:
2556a1cb98faSBarry Smith + dm                   - The `DM` into which the labels are loaded
2557a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved labels
255820f4b53cSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2559b08ad5deSksagiyam 
2560b08ad5deSksagiyam   Level: advanced
2561b08ad5deSksagiyam 
2562a1cb98faSBarry Smith   Note:
2563dc9a610eSPierre Jolivet   The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs.
2564e6368b79SVaclav Hapla 
25651cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2566a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
2567b08ad5deSksagiyam @*/
2568d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2569d71ae5a4SJacob Faibussowitsch {
2570b08ad5deSksagiyam   PetscBool ishdf5;
2571b08ad5deSksagiyam 
2572b08ad5deSksagiyam   PetscFunctionBegin;
2573b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2574b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2575e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
25769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2578b08ad5deSksagiyam   if (ishdf5) {
2579b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2580b08ad5deSksagiyam     PetscViewerFormat format;
2581b08ad5deSksagiyam 
25829566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2583966bd95aSPierre 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]);
25849566063dSJacob Faibussowitsch     PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2585b08ad5deSksagiyam #else
2586b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2587b08ad5deSksagiyam #endif
2588b08ad5deSksagiyam   }
25899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
25903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2591b08ad5deSksagiyam }
2592b08ad5deSksagiyam 
2593f84dd6b4Sksagiyam /*@
2594a1cb98faSBarry Smith   DMPlexSectionLoad - Loads section into a `DMPLEX`
2595f84dd6b4Sksagiyam 
259620f4b53cSBarry Smith   Collective
2597f84dd6b4Sksagiyam 
2598f84dd6b4Sksagiyam   Input Parameters:
2599a1cb98faSBarry Smith + dm                   - The `DM` that represents the topology
2600a1cb98faSBarry Smith . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
26010318f8a0SStefano Zampini . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL`
2602a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2603f84dd6b4Sksagiyam 
2604a4e35b19SJacob Faibussowitsch   Output Parameters:
260520f4b53cSBarry 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)
260620f4b53cSBarry 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)
2607f84dd6b4Sksagiyam 
2608f84dd6b4Sksagiyam   Level: advanced
2609f84dd6b4Sksagiyam 
2610f84dd6b4Sksagiyam   Notes:
261120f4b53cSBarry 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.
2612f84dd6b4Sksagiyam 
26130318f8a0SStefano 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.
2614f84dd6b4Sksagiyam 
261520f4b53cSBarry 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.
2616f84dd6b4Sksagiyam 
2617f84dd6b4Sksagiyam   Example using 2 processes:
2618a1cb98faSBarry Smith .vb
2619a1cb98faSBarry Smith   NX (number of points on dm): 4
2620a1cb98faSBarry Smith   sectionA                   : the on-disk section
2621a1cb98faSBarry Smith   vecA                       : a vector associated with sectionA
2622a1cb98faSBarry Smith   sectionB                   : sectiondm's local section constructed in this function
2623a1cb98faSBarry Smith   vecB (local)               : a vector associated with sectiondm's local section
2624a1cb98faSBarry Smith   vecB (global)              : a vector associated with sectiondm's global section
2625f84dd6b4Sksagiyam 
2626a1cb98faSBarry Smith                                      rank 0    rank 1
2627a1cb98faSBarry Smith   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2628a1cb98faSBarry Smith   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2629a1cb98faSBarry Smith   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2630a1cb98faSBarry Smith   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2631a1cb98faSBarry Smith   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2632a1cb98faSBarry Smith   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2633a1cb98faSBarry Smith   sectionB->atlasDof             :     1 0 1 | 1 3
2634a1cb98faSBarry Smith   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2635a1cb98faSBarry Smith   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2636a1cb98faSBarry Smith   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2637a1cb98faSBarry Smith .ve
2638a1cb98faSBarry Smith   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2639a1cb98faSBarry Smith 
26401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2641f84dd6b4Sksagiyam @*/
2642ce78bad3SBarry Smith PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF)
2643d71ae5a4SJacob Faibussowitsch {
2644f84dd6b4Sksagiyam   PetscBool ishdf5;
2645f84dd6b4Sksagiyam 
2646f84dd6b4Sksagiyam   PetscFunctionBegin;
2647f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2648f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
26490318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
2650f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2651f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
26524f572ea9SToby Isaac   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
26534f572ea9SToby Isaac   if (localDofSF) PetscAssertPointer(localDofSF, 6);
26549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
26559566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2656f84dd6b4Sksagiyam   if (ishdf5) {
2657f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
26589566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2659f84dd6b4Sksagiyam #else
2660f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2661f84dd6b4Sksagiyam #endif
2662f84dd6b4Sksagiyam   }
26639566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
26643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2665f84dd6b4Sksagiyam }
2666f84dd6b4Sksagiyam 
26678be3dfe1Sksagiyam /*@
26688be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
26698be3dfe1Sksagiyam 
267020f4b53cSBarry Smith   Collective
26718be3dfe1Sksagiyam 
26728be3dfe1Sksagiyam   Input Parameters:
2673a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2674a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
26750318f8a0SStefano Zampini . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2676a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
26778be3dfe1Sksagiyam - vec       - The global vector to set values of
26788be3dfe1Sksagiyam 
26798be3dfe1Sksagiyam   Level: advanced
26808be3dfe1Sksagiyam 
26818be3dfe1Sksagiyam   Notes:
26820318f8a0SStefano 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.
26838be3dfe1Sksagiyam 
268460225df5SJacob Faibussowitsch   Calling sequence:
2685a1cb98faSBarry Smith .vb
2686a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2687a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2688a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2689a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2690a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2691a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2692a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2693a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2694a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2695a1cb98faSBarry Smith        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2696a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2697a1cb98faSBarry Smith        PetscSFDestroy(&gsf);
2698a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2699a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2700a1cb98faSBarry Smith        DMDestroy(&dm);
2701a1cb98faSBarry Smith .ve
27028be3dfe1Sksagiyam 
27031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2704a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
27058be3dfe1Sksagiyam @*/
2706d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2707d71ae5a4SJacob Faibussowitsch {
27088be3dfe1Sksagiyam   PetscBool ishdf5;
27098be3dfe1Sksagiyam 
27108be3dfe1Sksagiyam   PetscFunctionBegin;
27118be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27128be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
27130318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
27148be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
27158be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
27168be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
27178be3dfe1Sksagiyam   /* Check consistency */
27188be3dfe1Sksagiyam   {
27198be3dfe1Sksagiyam     PetscSection section;
27208be3dfe1Sksagiyam     PetscBool    includesConstraints;
27218be3dfe1Sksagiyam     PetscInt     m, m1;
27228be3dfe1Sksagiyam 
27239566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
27249566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
27259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
27269566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
27279566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
272863a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
27298be3dfe1Sksagiyam   }
27309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
27319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
27328be3dfe1Sksagiyam   if (ishdf5) {
27338be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
27349566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
27358be3dfe1Sksagiyam #else
27368be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
27378be3dfe1Sksagiyam #endif
27388be3dfe1Sksagiyam   }
27399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
27403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27418be3dfe1Sksagiyam }
27428be3dfe1Sksagiyam 
27438be3dfe1Sksagiyam /*@
27448be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
27458be3dfe1Sksagiyam 
274620f4b53cSBarry Smith   Collective
27478be3dfe1Sksagiyam 
27488be3dfe1Sksagiyam   Input Parameters:
2749a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2750a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
27510318f8a0SStefano Zampini . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL`
2752a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
27538be3dfe1Sksagiyam - vec       - The local vector to set values of
27548be3dfe1Sksagiyam 
27558be3dfe1Sksagiyam   Level: advanced
27568be3dfe1Sksagiyam 
27578be3dfe1Sksagiyam   Notes:
27580318f8a0SStefano 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.
27598be3dfe1Sksagiyam 
276060225df5SJacob Faibussowitsch   Calling sequence:
2761a1cb98faSBarry Smith .vb
2762a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2763a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2764a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2765a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2766a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2767a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2768a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2769a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2770a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2771a1cb98faSBarry Smith        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2772a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2773a1cb98faSBarry Smith        PetscSFDestroy(&lsf);
2774a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2775a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2776a1cb98faSBarry Smith        DMDestroy(&dm);
2777a1cb98faSBarry Smith .ve
27788be3dfe1Sksagiyam 
27791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2780a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
27818be3dfe1Sksagiyam @*/
2782d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2783d71ae5a4SJacob Faibussowitsch {
27848be3dfe1Sksagiyam   PetscBool ishdf5;
27858be3dfe1Sksagiyam 
27868be3dfe1Sksagiyam   PetscFunctionBegin;
27878be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27888be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
27890318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
27908be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
27918be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
27928be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
27938be3dfe1Sksagiyam   /* Check consistency */
27948be3dfe1Sksagiyam   {
27958be3dfe1Sksagiyam     PetscSection section;
27968be3dfe1Sksagiyam     PetscBool    includesConstraints;
27978be3dfe1Sksagiyam     PetscInt     m, m1;
27988be3dfe1Sksagiyam 
27999566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
28009566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
28019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
28029566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
28039566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
280463a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
28058be3dfe1Sksagiyam   }
28069566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
28079566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
28088be3dfe1Sksagiyam   if (ishdf5) {
28098be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
28109566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
28118be3dfe1Sksagiyam #else
28128be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
28138be3dfe1Sksagiyam #endif
28148be3dfe1Sksagiyam   }
28159566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
28163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28178be3dfe1Sksagiyam }
28188be3dfe1Sksagiyam 
2819d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2820d71ae5a4SJacob Faibussowitsch {
2821552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2822552f7358SJed Brown 
2823552f7358SJed Brown   PetscFunctionBegin;
28249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
28259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
282601468941SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
282701468941SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL));
28289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
28299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
28302e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
28312e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
28322e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
28332e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
28346bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
28356bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2836adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL));
2837adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL));
2838adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL));
2839adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL));
2840c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2841c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2842d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2843d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
28445f06a3ddSJed Brown   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
28453ba16761SJacob Faibussowitsch   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
28469566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
28479566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
28489566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
28499566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
28509566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
28519566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
285221027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
28539f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
28549566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
28559566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
28569566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
28571d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
28589566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
28599566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
28609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
28619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
28629566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
28631fca310dSJames Wright   if (mesh->periodic.face_sfs) {
28641fca310dSJames Wright     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i]));
28651fca310dSJames Wright     PetscCall(PetscFree(mesh->periodic.face_sfs));
28661fca310dSJames Wright   }
28676725e60dSJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2868b83f62b0SJames Wright   if (mesh->periodic.periodic_points) {
2869b83f62b0SJames Wright     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i]));
2870b83f62b0SJames Wright     PetscCall(PetscFree(mesh->periodic.periodic_points));
2871b83f62b0SJames Wright   }
28721fca310dSJames Wright   if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform));
28739566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
28749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
28759566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
28769566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
28779566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
28789566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
28799566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
28809566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
28819566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
28829566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
28839566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2884c29ce622SStefano Zampini   if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm));
288561f058f9SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->transform));
2886552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
28879566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
28883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2889552f7358SJed Brown }
2890552f7358SJed Brown 
2891d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2892d71ae5a4SJacob Faibussowitsch {
2893d02c7345SMatthew G. Knepley   PetscSection           sectionGlobal, sectionLocal;
2894acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
28959fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2896837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2897b412c318SBarry Smith   MatType                mtype;
28981428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2899552f7358SJed Brown 
2900552f7358SJed Brown   PetscFunctionBegin;
29019566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2902b412c318SBarry Smith   mtype = dm->mattype;
2903d02c7345SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &sectionLocal));
29049566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
29059566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
29069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
29079fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
29089566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
29099566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
29109566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
29119566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
29129566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2913acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
29149566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
29159566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
29169566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
29179566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
29189566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
29199566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
29209566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
29219566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2922552f7358SJed Brown   if (!isShell) {
29231c6742e7SMatthew G. Knepley     // There are three states with pblocks, since block starts can have no dofs:
29241c6742e7SMatthew G. Knepley     // UNKNOWN) New Block:   An open block has been signalled by pblocks[p] == 1
29251c6742e7SMatthew G. Knepley     // TRUE)    Block Start: The first entry in a block has been added
29261c6742e7SMatthew G. Knepley     // FALSE)   Block Add:   An additional block entry has been added, since pblocks[p] == 0
29271c6742e7SMatthew G. Knepley     PetscBT         blst;
29281c6742e7SMatthew G. Knepley     PetscBool3      bstate     = PETSC_BOOL3_UNKNOWN;
2929837628f4SStefano Zampini     PetscBool       fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
29301c6742e7SMatthew G. Knepley     const PetscInt *perm       = NULL;
29319fca9976SJed Brown     PetscInt       *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
29321c6742e7SMatthew G. Knepley     PetscInt        pStart, pEnd, dof, cdof, num_fields;
2933552f7358SJed Brown 
29349566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
29351c6742e7SMatthew G. Knepley     PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst));
29361c6742e7SMatthew G. Knepley     if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm));
29379fca9976SJed Brown 
29389fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
29399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2940863027abSJed Brown     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
29411c6742e7SMatthew G. Knepley     // We need to process in the permuted order to get block sizes right
29421c6742e7SMatthew G. Knepley     for (PetscInt point = pStart; point < pEnd; ++point) {
29431c6742e7SMatthew G. Knepley       const PetscInt p = perm ? perm[point] : point;
29441c6742e7SMatthew G. Knepley 
2945863027abSJed Brown       switch (dm->blocking_type) {
29460e762ea3SJed Brown       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
29479fca9976SJed Brown         PetscInt bdof, offset;
2948a9d99c84SMatthew G. Knepley 
29499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
29509fca9976SJed Brown         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
29519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
29521c6742e7SMatthew G. Knepley         if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN;
295332b27637SMatthew G. Knepley         if (dof > 0) {
29541c6742e7SMatthew G. Knepley           // State change
29551c6742e7SMatthew G. Knepley           if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE;
29561c6742e7SMatthew G. Knepley           else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE;
29571c6742e7SMatthew G. Knepley 
2958d02c7345SMatthew G. Knepley           for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof;
2959d02c7345SMatthew G. Knepley           // Signal block concatenation
29601c6742e7SMatthew G. Knepley           if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof);
296132b27637SMatthew G. Knepley         }
29621d17a0a3SMatthew G. Knepley         dof  = dof < 0 ? -(dof + 1) : dof;
29631d17a0a3SMatthew G. Knepley         bdof = cdof && (dof - cdof) ? 1 : dof;
29641d17a0a3SMatthew G. Knepley         if (dof) {
29659371c9d4SSatish Balay           if (bs < 0) {
29669371c9d4SSatish Balay             bs = bdof;
29679371c9d4SSatish Balay           } else if (bs != bdof) {
29689371c9d4SSatish Balay             bs = 1;
29699371c9d4SSatish Balay           }
2970552f7358SJed Brown         }
2971863027abSJed Brown       } break;
2972863027abSJed Brown       case DM_BLOCKING_FIELD_NODE: {
2973863027abSJed Brown         for (PetscInt field = 0; field < num_fields; field++) {
2974863027abSJed Brown           PetscInt num_comp, bdof, offset;
2975863027abSJed Brown           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2976863027abSJed Brown           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2977863027abSJed Brown           if (dof < 0) continue;
2978863027abSJed Brown           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2979863027abSJed Brown           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2980863027abSJed 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);
2981863027abSJed Brown           PetscInt num_nodes = dof / num_comp;
2982863027abSJed Brown           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2983863027abSJed Brown           // Handle possibly constant block size (unlikely)
2984863027abSJed Brown           bdof = cdof && (dof - cdof) ? 1 : dof;
2985863027abSJed Brown           if (dof) {
2986863027abSJed Brown             if (bs < 0) {
2987863027abSJed Brown               bs = bdof;
2988863027abSJed Brown             } else if (bs != bdof) {
2989863027abSJed Brown               bs = 1;
2990863027abSJed Brown             }
2991863027abSJed Brown           }
2992863027abSJed Brown         }
2993863027abSJed Brown       } break;
2994863027abSJed Brown       }
29952a28c762SMatthew G Knepley     }
29961c6742e7SMatthew G. Knepley     if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm));
29972a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
29981690c2aeSBarry Smith     bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
2999e432b41dSStefano Zampini     bsLocal[1] = bs;
30009566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
3001e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
3002e432b41dSStefano Zampini     else bs = bsMinMax[0];
30036fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
30049566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
30050682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
30069566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
30079566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
30080682b8bbSJed Brown     } else {
30099566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
30109566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
30119566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
3012552f7358SJed Brown     }
301332b27637SMatthew G. Knepley     if (pblocks) { // Consolidate blocks
30149fca9976SJed Brown       PetscInt nblocks = 0;
301532b27637SMatthew G. Knepley       pblocks[0]       = PetscAbs(pblocks[0]);
30169fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
30179fca9976SJed Brown         if (pblocks[i] == 0) continue;
3018d02c7345SMatthew G. Knepley         // Negative block size indicates the blocks should be concatenated
3019d02c7345SMatthew G. Knepley         if (pblocks[i] < 0) {
3020d02c7345SMatthew G. Knepley           pblocks[i] = -pblocks[i];
3021d02c7345SMatthew G. Knepley           pblocks[nblocks - 1] += pblocks[i];
3022d02c7345SMatthew G. Knepley         } else {
30239fca9976SJed Brown           pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
3024d02c7345SMatthew G. Knepley         }
30251c6742e7SMatthew G. Knepley         for (PetscInt j = 1; j < pblocks[i]; j++)
30261c6742e7SMatthew 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);
30279fca9976SJed Brown       }
30289fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
30299fca9976SJed Brown     }
30309fca9976SJed Brown     PetscCall(PetscFree(pblocks));
3031aa0f6e3cSJed Brown   }
30329566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
30333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3034552f7358SJed Brown }
3035552f7358SJed Brown 
30367cd05799SMatthew G. Knepley /*@
3037a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
3038be36d101SStefano Zampini 
3039a1cb98faSBarry Smith   Not Collective
3040be36d101SStefano Zampini 
3041be36d101SStefano Zampini   Input Parameter:
304260225df5SJacob Faibussowitsch . dm - The `DMPLEX`
3043be36d101SStefano Zampini 
30442fe279fdSBarry Smith   Output Parameter:
3045be36d101SStefano Zampini . subsection - The subdomain section
3046be36d101SStefano Zampini 
3047be36d101SStefano Zampini   Level: developer
3048be36d101SStefano Zampini 
30491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
30507cd05799SMatthew G. Knepley @*/
3051d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
3052d71ae5a4SJacob Faibussowitsch {
3053be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
3054be36d101SStefano Zampini 
3055be36d101SStefano Zampini   PetscFunctionBegin;
3056be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3057be36d101SStefano Zampini   if (!mesh->subdomainSection) {
3058be36d101SStefano Zampini     PetscSection section;
3059be36d101SStefano Zampini     PetscSF      sf;
3060be36d101SStefano Zampini 
30619566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
30629566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
3063eb9d3e4dSMatthew G. Knepley     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
30649566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
3065be36d101SStefano Zampini   }
3066be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
30673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3068be36d101SStefano Zampini }
3069be36d101SStefano Zampini 
3070552f7358SJed Brown /*@
307120f4b53cSBarry Smith   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
3072552f7358SJed Brown 
3073a1cb98faSBarry Smith   Not Collective
3074552f7358SJed Brown 
3075552f7358SJed Brown   Input Parameter:
307660225df5SJacob Faibussowitsch . dm - The `DMPLEX`
3077552f7358SJed Brown 
3078552f7358SJed Brown   Output Parameters:
3079552f7358SJed Brown + pStart - The first mesh point
3080552f7358SJed Brown - pEnd   - The upper bound for mesh points
3081552f7358SJed Brown 
3082552f7358SJed Brown   Level: beginner
3083552f7358SJed Brown 
30841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
3085552f7358SJed Brown @*/
3086d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
3087d71ae5a4SJacob Faibussowitsch {
3088552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3089552f7358SJed Brown 
3090552f7358SJed Brown   PetscFunctionBegin;
3091552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30929f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
30939f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
30943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3095552f7358SJed Brown }
3096552f7358SJed Brown 
3097552f7358SJed Brown /*@
309820f4b53cSBarry Smith   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
3099552f7358SJed Brown 
3100a1cb98faSBarry Smith   Not Collective
3101552f7358SJed Brown 
3102552f7358SJed Brown   Input Parameters:
310360225df5SJacob Faibussowitsch + dm     - The `DMPLEX`
3104552f7358SJed Brown . pStart - The first mesh point
3105552f7358SJed Brown - pEnd   - The upper bound for mesh points
3106552f7358SJed Brown 
3107552f7358SJed Brown   Level: beginner
3108552f7358SJed Brown 
31091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
3110552f7358SJed Brown @*/
3111d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
3112d71ae5a4SJacob Faibussowitsch {
3113552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3114552f7358SJed Brown 
3115552f7358SJed Brown   PetscFunctionBegin;
3116552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31179566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
31189566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
311921027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
31203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3121552f7358SJed Brown }
3122552f7358SJed Brown 
3123552f7358SJed Brown /*@
3124eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
3125552f7358SJed Brown 
3126a1cb98faSBarry Smith   Not Collective
3127552f7358SJed Brown 
3128552f7358SJed Brown   Input Parameters:
312960225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3130a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3131552f7358SJed Brown 
3132552f7358SJed Brown   Output Parameter:
313320f4b53cSBarry Smith . size - The cone size for point `p`
3134552f7358SJed Brown 
3135552f7358SJed Brown   Level: beginner
3136552f7358SJed Brown 
31371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3138552f7358SJed Brown @*/
3139d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
3140d71ae5a4SJacob Faibussowitsch {
3141552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3142552f7358SJed Brown 
3143552f7358SJed Brown   PetscFunctionBegin;
3144552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31454f572ea9SToby Isaac   PetscAssertPointer(size, 3);
31469f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
31479f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
31483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3149552f7358SJed Brown }
3150552f7358SJed Brown 
3151552f7358SJed Brown /*@
3152eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
3153552f7358SJed Brown 
3154a1cb98faSBarry Smith   Not Collective
3155552f7358SJed Brown 
3156552f7358SJed Brown   Input Parameters:
315760225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3158a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
315920f4b53cSBarry Smith - size - The cone size for point `p`
3160552f7358SJed Brown 
3161552f7358SJed Brown   Level: beginner
3162552f7358SJed Brown 
3163a1cb98faSBarry Smith   Note:
3164a1cb98faSBarry Smith   This should be called after `DMPlexSetChart()`.
3165a1cb98faSBarry Smith 
31662c9a7b26SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
3167552f7358SJed Brown @*/
3168d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
3169d71ae5a4SJacob Faibussowitsch {
3170552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3171552f7358SJed Brown 
3172552f7358SJed Brown   PetscFunctionBegin;
3173552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31749f4ada15SMatthew G. Knepley   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
31759566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
31763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3177552f7358SJed Brown }
3178552f7358SJed Brown 
3179552f7358SJed Brown /*@C
3180eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
3181552f7358SJed Brown 
3182a1cb98faSBarry Smith   Not Collective
3183552f7358SJed Brown 
3184552f7358SJed Brown   Input Parameters:
3185a1cb98faSBarry Smith + dm - The `DMPLEX`
3186a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3187552f7358SJed Brown 
3188552f7358SJed Brown   Output Parameter:
31892c9a7b26SBarry Smith . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()`
3190552f7358SJed Brown 
3191552f7358SJed Brown   Level: beginner
3192552f7358SJed Brown 
319360225df5SJacob Faibussowitsch   Fortran Notes:
31942c9a7b26SBarry Smith   `cone` must be declared with
31952c9a7b26SBarry Smith .vb
31962c9a7b26SBarry Smith   PetscInt, pointer :: cone(:)
31972c9a7b26SBarry Smith .ve
31982c9a7b26SBarry Smith 
3199feaf08eaSBarry Smith   You must call `DMPlexRestoreCone()` after you finish using the array.
3200a1cb98faSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
32013813dfbdSMatthew G Knepley 
32021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3203552f7358SJed Brown @*/
3204d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3205d71ae5a4SJacob Faibussowitsch {
3206552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3207552f7358SJed Brown   PetscInt off;
3208552f7358SJed Brown 
3209552f7358SJed Brown   PetscFunctionBegin;
3210552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32114f572ea9SToby Isaac   PetscAssertPointer(cone, 3);
32129566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
32138e3a54c0SPierre Jolivet   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
32143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3215552f7358SJed Brown }
3216552f7358SJed Brown 
3217cc4c1da9SBarry Smith /*@
32180ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
32190ce7577fSVaclav Hapla 
3220a1cb98faSBarry Smith   Not Collective
32210ce7577fSVaclav Hapla 
32220ce7577fSVaclav Hapla   Input Parameters:
3223a1cb98faSBarry Smith + dm - The `DMPLEX`
3224a1cb98faSBarry Smith - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
32250ce7577fSVaclav Hapla 
3226d8d19677SJose E. Roman   Output Parameters:
322720f4b53cSBarry Smith + pConesSection - `PetscSection` describing the layout of `pCones`
32282c9a7b26SBarry Smith - pCones        - An `IS` containing the points which are on the in-edges for the point set `p`
32290ce7577fSVaclav Hapla 
32300ce7577fSVaclav Hapla   Level: intermediate
32310ce7577fSVaclav Hapla 
32321cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
32330ce7577fSVaclav Hapla @*/
3234ce78bad3SBarry Smith PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones)
3235d71ae5a4SJacob Faibussowitsch {
32360ce7577fSVaclav Hapla   PetscSection cs, newcs;
32370ce7577fSVaclav Hapla   PetscInt    *cones;
32380ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
32390ce7577fSVaclav Hapla   PetscInt     n;
32400ce7577fSVaclav Hapla 
32410ce7577fSVaclav Hapla   PetscFunctionBegin;
32429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
32439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
32449566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
32450ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
32460ce7577fSVaclav Hapla   if (pCones) {
32479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
32489566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
32490ce7577fSVaclav Hapla   }
32503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32510ce7577fSVaclav Hapla }
32520ce7577fSVaclav Hapla 
3253af9eab45SVaclav Hapla /*@
3254af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
3255d4636a37SVaclav Hapla 
3256a1cb98faSBarry Smith   Not Collective
3257d4636a37SVaclav Hapla 
3258d4636a37SVaclav Hapla   Input Parameters:
3259a1cb98faSBarry Smith + dm     - The `DMPLEX`
3260a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3261d4636a37SVaclav Hapla 
3262d4636a37SVaclav Hapla   Output Parameter:
32632c9a7b26SBarry Smith . expandedPoints - An `IS` containing the of vertices recursively expanded from input points
3264d4636a37SVaclav Hapla 
3265d4636a37SVaclav Hapla   Level: advanced
3266d4636a37SVaclav Hapla 
3267af9eab45SVaclav Hapla   Notes:
326820f4b53cSBarry Smith   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
3269af9eab45SVaclav Hapla 
3270a1cb98faSBarry Smith   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
3271a1cb98faSBarry Smith 
32721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3273a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`
3274d4636a37SVaclav Hapla @*/
3275d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3276d71ae5a4SJacob Faibussowitsch {
3277af9eab45SVaclav Hapla   IS      *expandedPointsAll;
3278af9eab45SVaclav Hapla   PetscInt depth;
3279d4636a37SVaclav Hapla 
3280d4636a37SVaclav Hapla   PetscFunctionBegin;
3281af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3282af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
32834f572ea9SToby Isaac   PetscAssertPointer(expandedPoints, 3);
32849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3285af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
32869566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
32879566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
32883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3289af9eab45SVaclav Hapla }
3290af9eab45SVaclav Hapla 
3291af9eab45SVaclav Hapla /*@
32922c9a7b26SBarry Smith   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices
32932c9a7b26SBarry Smith   (DAG points of depth 0, i.e., without cones).
3294af9eab45SVaclav Hapla 
3295a1cb98faSBarry Smith   Not Collective
3296af9eab45SVaclav Hapla 
3297af9eab45SVaclav Hapla   Input Parameters:
3298a1cb98faSBarry Smith + dm     - The `DMPLEX`
3299a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3300af9eab45SVaclav Hapla 
3301d8d19677SJose E. Roman   Output Parameters:
3302a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3303af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
3304af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3305af9eab45SVaclav Hapla 
3306af9eab45SVaclav Hapla   Level: advanced
3307af9eab45SVaclav Hapla 
3308af9eab45SVaclav Hapla   Notes:
3309a1cb98faSBarry Smith   Like `DMPlexGetConeTuple()` but recursive.
3310af9eab45SVaclav Hapla 
3311a4e35b19SJacob 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.
3312af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
3313af9eab45SVaclav Hapla 
3314a4e35b19SJacob 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\:
3315a4e35b19SJacob Faibussowitsch   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3316a4e35b19SJacob Faibussowitsch   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
3317af9eab45SVaclav Hapla 
33181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3319a1cb98faSBarry Smith           `DMPlexGetDepth()`, `PetscSection`, `IS`
3320af9eab45SVaclav Hapla @*/
3321ce78bad3SBarry Smith PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[])
3322d71ae5a4SJacob Faibussowitsch {
3323af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
3324af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
3325af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3326af9eab45SVaclav Hapla   IS             *expandedPoints_;
3327af9eab45SVaclav Hapla   PetscSection   *sections_;
3328af9eab45SVaclav Hapla 
3329af9eab45SVaclav Hapla   PetscFunctionBegin;
3330af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3331af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
33324f572ea9SToby Isaac   if (depth) PetscAssertPointer(depth, 3);
33334f572ea9SToby Isaac   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
33344f572ea9SToby Isaac   if (sections) PetscAssertPointer(sections, 5);
33359566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
33369566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
33379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
33389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
33399566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
3340af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3341af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
33429566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
33439566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3344af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
33459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3346af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
33479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
33489566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3349af9eab45SVaclav Hapla       } else {
33509566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3351af9eab45SVaclav Hapla       }
3352af9eab45SVaclav Hapla     }
33539566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
33549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
33559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
3356af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
33579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
33589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3359af9eab45SVaclav Hapla       if (cn > 1) {
33609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3361418fb43bSPierre Jolivet         PetscCall(PetscArraycpy(&newarr[co], cone, cn));
3362af9eab45SVaclav Hapla       } else {
3363af9eab45SVaclav Hapla         newarr[co] = arr[i];
3364af9eab45SVaclav Hapla       }
3365af9eab45SVaclav Hapla     }
33669566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3367af9eab45SVaclav Hapla     arr = newarr;
3368af9eab45SVaclav Hapla     n   = newn;
3369af9eab45SVaclav Hapla   }
33709566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
3371af9eab45SVaclav Hapla   *depth = depth_;
3372af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
3373af9eab45SVaclav Hapla   else {
33749566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
33759566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
3376af9eab45SVaclav Hapla   }
3377af9eab45SVaclav Hapla   if (sections) *sections = sections_;
3378af9eab45SVaclav Hapla   else {
33799566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
33809566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
3381af9eab45SVaclav Hapla   }
33823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3383af9eab45SVaclav Hapla }
3384af9eab45SVaclav Hapla 
3385af9eab45SVaclav Hapla /*@
3386a1cb98faSBarry Smith   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3387af9eab45SVaclav Hapla 
3388a1cb98faSBarry Smith   Not Collective
3389af9eab45SVaclav Hapla 
3390af9eab45SVaclav Hapla   Input Parameters:
3391a1cb98faSBarry Smith + dm     - The `DMPLEX`
3392a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3393af9eab45SVaclav Hapla 
3394d8d19677SJose E. Roman   Output Parameters:
3395a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3396af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3397af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3398af9eab45SVaclav Hapla 
3399af9eab45SVaclav Hapla   Level: advanced
3400af9eab45SVaclav Hapla 
3401a1cb98faSBarry Smith   Note:
3402a1cb98faSBarry Smith   See `DMPlexGetConeRecursive()`
3403af9eab45SVaclav Hapla 
34041cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3405a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`, `PetscSection`
3406af9eab45SVaclav Hapla @*/
3407ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[])
3408d71ae5a4SJacob Faibussowitsch {
3409af9eab45SVaclav Hapla   PetscInt d, depth_;
3410af9eab45SVaclav Hapla 
3411af9eab45SVaclav Hapla   PetscFunctionBegin;
34129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
34131dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3414af9eab45SVaclav Hapla   if (depth) *depth = 0;
3415af9eab45SVaclav Hapla   if (expandedPoints) {
341657508eceSPierre Jolivet     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d]));
34179566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3418af9eab45SVaclav Hapla   }
3419af9eab45SVaclav Hapla   if (sections) {
342057508eceSPierre Jolivet     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d]));
34219566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3422af9eab45SVaclav Hapla   }
34233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3424d4636a37SVaclav Hapla }
3425d4636a37SVaclav Hapla 
3426552f7358SJed Brown /*@
342792371b87SBarry 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
3428552f7358SJed Brown 
3429a1cb98faSBarry Smith   Not Collective
3430552f7358SJed Brown 
3431552f7358SJed Brown   Input Parameters:
343260225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3433a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
34342c9a7b26SBarry Smith - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()`
3435552f7358SJed Brown 
3436552f7358SJed Brown   Level: beginner
3437552f7358SJed Brown 
3438a1cb98faSBarry Smith   Note:
3439a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3440a1cb98faSBarry Smith 
34411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3442552f7358SJed Brown @*/
3443d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3444d71ae5a4SJacob Faibussowitsch {
3445552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3446552f7358SJed Brown   PetscInt dof, off, c;
3447552f7358SJed Brown 
3448552f7358SJed Brown   PetscFunctionBegin;
3449552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
34514f572ea9SToby Isaac   if (dof) PetscAssertPointer(cone, 3);
34529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3453db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3454db485b19SStefano Zampini     PetscInt pStart, pEnd;
3455db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
345663a3b9bcSJacob 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);
3457552f7358SJed Brown     for (c = 0; c < dof; ++c) {
345863a3b9bcSJacob 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);
3459552f7358SJed Brown       mesh->cones[off + c] = cone[c];
3460552f7358SJed Brown     }
3461db485b19SStefano Zampini   } else {
3462db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3463db485b19SStefano Zampini   }
34643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3465552f7358SJed Brown }
3466552f7358SJed Brown 
3467552f7358SJed Brown /*@C
3468eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3469552f7358SJed Brown 
3470a1cb98faSBarry Smith   Not Collective
3471552f7358SJed Brown 
3472552f7358SJed Brown   Input Parameters:
347360225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3474a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3475552f7358SJed Brown 
3476552f7358SJed Brown   Output Parameter:
347720f4b53cSBarry Smith . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
34782c9a7b26SBarry Smith                     integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()`
3479552f7358SJed Brown 
3480552f7358SJed Brown   Level: beginner
3481552f7358SJed Brown 
3482a1cb98faSBarry Smith   Note:
3483b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3484b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3485a1cb98faSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3486b5a892a1SMatthew G. Knepley   with the identity.
3487b5a892a1SMatthew G. Knepley 
348860225df5SJacob Faibussowitsch   Fortran Notes:
34892c9a7b26SBarry Smith   You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3490a1cb98faSBarry Smith   `DMPlexRestoreConeOrientation()` is not needed/available in C.
34913813dfbdSMatthew G Knepley 
34922c9a7b26SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`,
34932c9a7b26SBarry Smith           `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3494552f7358SJed Brown @*/
3495d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3496d71ae5a4SJacob Faibussowitsch {
3497552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3498552f7358SJed Brown   PetscInt off;
3499552f7358SJed Brown 
3500552f7358SJed Brown   PetscFunctionBegin;
3501552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
350276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3503552f7358SJed Brown     PetscInt dof;
35049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
35054f572ea9SToby Isaac     if (dof) PetscAssertPointer(coneOrientation, 3);
3506552f7358SJed Brown   }
35079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
35080d644c17SKarl Rupp 
3509552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
35103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3511552f7358SJed Brown }
3512552f7358SJed Brown 
3513552f7358SJed Brown /*@
3514eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3515552f7358SJed Brown 
3516a1cb98faSBarry Smith   Not Collective
3517552f7358SJed Brown 
3518552f7358SJed Brown   Input Parameters:
351960225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3520a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
35212c9a7b26SBarry Smith - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()`
3522b5a892a1SMatthew G. Knepley 
3523552f7358SJed Brown   Level: beginner
3524552f7358SJed Brown 
3525a1cb98faSBarry Smith   Notes:
3526a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3527a1cb98faSBarry Smith 
3528a1cb98faSBarry Smith   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3529a1cb98faSBarry Smith 
35301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3531552f7358SJed Brown @*/
3532d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3533d71ae5a4SJacob Faibussowitsch {
3534552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3535552f7358SJed Brown   PetscInt pStart, pEnd;
3536552f7358SJed Brown   PetscInt dof, off, c;
3537552f7358SJed Brown 
3538552f7358SJed Brown   PetscFunctionBegin;
3539552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
35414f572ea9SToby Isaac   if (dof) PetscAssertPointer(coneOrientation, 3);
35429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3543db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3544db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
354563a3b9bcSJacob 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);
3546552f7358SJed Brown     for (c = 0; c < dof; ++c) {
3547552f7358SJed Brown       PetscInt cdof, o = coneOrientation[c];
3548552f7358SJed Brown 
35499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
35501dca8a05SBarry 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);
3551552f7358SJed Brown       mesh->coneOrientations[off + c] = o;
3552552f7358SJed Brown     }
3553db485b19SStefano Zampini   } else {
3554db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3555db485b19SStefano Zampini   }
35563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3557552f7358SJed Brown }
3558552f7358SJed Brown 
35597cd05799SMatthew G. Knepley /*@
3560eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
35617cd05799SMatthew G. Knepley 
3562a1cb98faSBarry Smith   Not Collective
35637cd05799SMatthew G. Knepley 
35647cd05799SMatthew G. Knepley   Input Parameters:
356560225df5SJacob Faibussowitsch + dm        - The `DMPLEX`
3566a1cb98faSBarry Smith . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
35677cd05799SMatthew G. Knepley . conePos   - The local index in the cone where the point should be put
35687cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
35697cd05799SMatthew G. Knepley 
35707cd05799SMatthew G. Knepley   Level: beginner
35717cd05799SMatthew G. Knepley 
35721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
35737cd05799SMatthew G. Knepley @*/
3574d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3575d71ae5a4SJacob Faibussowitsch {
3576552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3577552f7358SJed Brown   PetscInt pStart, pEnd;
3578552f7358SJed Brown   PetscInt dof, off;
3579552f7358SJed Brown 
3580552f7358SJed Brown   PetscFunctionBegin;
3581552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3582a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
35839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
358463a3b9bcSJacob 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);
358563a3b9bcSJacob 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);
35869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
358763a3b9bcSJacob 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);
3588a03d55ffSStefano Zampini   }
3589a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3590552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
35913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3592552f7358SJed Brown }
3593552f7358SJed Brown 
35947cd05799SMatthew G. Knepley /*@
3595eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
35967cd05799SMatthew G. Knepley 
3597a1cb98faSBarry Smith   Not Collective
35987cd05799SMatthew G. Knepley 
35997cd05799SMatthew G. Knepley   Input Parameters:
360060225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3601a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
36027cd05799SMatthew G. Knepley . conePos         - The local index in the cone where the point should be put
36037cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
36047cd05799SMatthew G. Knepley 
36057cd05799SMatthew G. Knepley   Level: beginner
36067cd05799SMatthew G. Knepley 
3607a1cb98faSBarry Smith   Note:
3608a1cb98faSBarry Smith   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3609b5a892a1SMatthew G. Knepley 
36101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
36117cd05799SMatthew G. Knepley @*/
3612d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3613d71ae5a4SJacob Faibussowitsch {
361477c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
361577c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
361677c88f5bSMatthew G Knepley   PetscInt dof, off;
361777c88f5bSMatthew G Knepley 
361877c88f5bSMatthew G Knepley   PetscFunctionBegin;
361977c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3620a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
36219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
362263a3b9bcSJacob 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);
36239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
362463a3b9bcSJacob 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);
3625a03d55ffSStefano Zampini   }
3626a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
362777c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
36283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
362977c88f5bSMatthew G Knepley }
363077c88f5bSMatthew G Knepley 
36319f4ada15SMatthew G. Knepley /*@C
36329f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
36339f4ada15SMatthew G. Knepley 
36349f4ada15SMatthew G. Knepley   Not collective
36359f4ada15SMatthew G. Knepley 
36369f4ada15SMatthew G. Knepley   Input Parameters:
36379f4ada15SMatthew G. Knepley + dm - The DMPlex
36389f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
36399f4ada15SMatthew G. Knepley 
36409f4ada15SMatthew G. Knepley   Output Parameters:
364120f4b53cSBarry Smith + cone - An array of points which are on the in-edges for point `p`
364220f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
36439f4ada15SMatthew G. Knepley          integer giving the prescription for cone traversal.
36449f4ada15SMatthew G. Knepley 
36459f4ada15SMatthew G. Knepley   Level: beginner
36469f4ada15SMatthew G. Knepley 
36479f4ada15SMatthew G. Knepley   Notes:
36489f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
36499f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
365020f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
36519f4ada15SMatthew G. Knepley   with the identity.
36529f4ada15SMatthew G. Knepley 
36532c9a7b26SBarry Smith   You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array.
36542c9a7b26SBarry Smith 
36559f4ada15SMatthew G. Knepley   Fortran Notes:
36562c9a7b26SBarry Smith   `cone` and `ornt` must be declared with
36572c9a7b26SBarry Smith .vb
36582c9a7b26SBarry Smith   PetscInt, pointer :: cone(:)
36592c9a7b26SBarry Smith   PetscInt, pointer :: ornt(:)
36602c9a7b26SBarry Smith .ve
36619f4ada15SMatthew G. Knepley 
36621cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
36639f4ada15SMatthew G. Knepley @*/
3664ce78bad3SBarry Smith PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[])
36659f4ada15SMatthew G. Knepley {
36669f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
36679f4ada15SMatthew G. Knepley 
36689f4ada15SMatthew G. Knepley   PetscFunctionBegin;
36699f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36709f4ada15SMatthew G. Knepley   if (mesh->tr) {
36719f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
36729f4ada15SMatthew G. Knepley   } else {
36739f4ada15SMatthew G. Knepley     PetscInt off;
36749f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
36759f4ada15SMatthew G. Knepley       PetscInt dof;
36769f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
36779f4ada15SMatthew G. Knepley       if (dof) {
36784f572ea9SToby Isaac         if (cone) PetscAssertPointer(cone, 3);
36794f572ea9SToby Isaac         if (ornt) PetscAssertPointer(ornt, 4);
36809f4ada15SMatthew G. Knepley       }
36819f4ada15SMatthew G. Knepley     }
36829f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
36838e3a54c0SPierre Jolivet     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
36848e3a54c0SPierre Jolivet     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
36859f4ada15SMatthew G. Knepley   }
36863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36879f4ada15SMatthew G. Knepley }
36889f4ada15SMatthew G. Knepley 
36899f4ada15SMatthew G. Knepley /*@C
36902c9a7b26SBarry Smith   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()`
36919f4ada15SMatthew G. Knepley 
369220f4b53cSBarry Smith   Not Collective
36939f4ada15SMatthew G. Knepley 
36949f4ada15SMatthew G. Knepley   Input Parameters:
36959f4ada15SMatthew G. Knepley + dm   - The DMPlex
369620f4b53cSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
36979f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
369820f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
36999f4ada15SMatthew G. Knepley          integer giving the prescription for cone traversal.
37009f4ada15SMatthew G. Knepley 
37019f4ada15SMatthew G. Knepley   Level: beginner
37029f4ada15SMatthew G. Knepley 
37031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
37049f4ada15SMatthew G. Knepley @*/
37059f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
37069f4ada15SMatthew G. Knepley {
37079f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
37089f4ada15SMatthew G. Knepley 
37099f4ada15SMatthew G. Knepley   PetscFunctionBegin;
37109f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37119f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
37123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37139f4ada15SMatthew G. Knepley }
37149f4ada15SMatthew G. Knepley 
3715552f7358SJed Brown /*@
3716eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3717552f7358SJed Brown 
3718a1cb98faSBarry Smith   Not Collective
3719552f7358SJed Brown 
3720552f7358SJed Brown   Input Parameters:
372160225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3722a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3723552f7358SJed Brown 
3724552f7358SJed Brown   Output Parameter:
372520f4b53cSBarry Smith . size - The support size for point `p`
3726552f7358SJed Brown 
3727552f7358SJed Brown   Level: beginner
3728552f7358SJed Brown 
37291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3730552f7358SJed Brown @*/
3731d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3732d71ae5a4SJacob Faibussowitsch {
3733552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3734552f7358SJed Brown 
3735552f7358SJed Brown   PetscFunctionBegin;
3736552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37374f572ea9SToby Isaac   PetscAssertPointer(size, 3);
37389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
37393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3740552f7358SJed Brown }
3741552f7358SJed Brown 
3742552f7358SJed Brown /*@
3743eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3744552f7358SJed Brown 
3745a1cb98faSBarry Smith   Not Collective
3746552f7358SJed Brown 
3747552f7358SJed Brown   Input Parameters:
374860225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3749a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
375020f4b53cSBarry Smith - size - The support size for point `p`
3751552f7358SJed Brown 
3752a1cb98faSBarry Smith   Level: beginner
3753552f7358SJed Brown 
3754552f7358SJed Brown   Note:
375520f4b53cSBarry Smith   This should be called after `DMPlexSetChart()`.
3756552f7358SJed Brown 
37571cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3758552f7358SJed Brown @*/
3759d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3760d71ae5a4SJacob Faibussowitsch {
3761552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3762552f7358SJed Brown 
3763552f7358SJed Brown   PetscFunctionBegin;
3764552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
37663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3767552f7358SJed Brown }
3768552f7358SJed Brown 
3769552f7358SJed Brown /*@C
3770eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3771552f7358SJed Brown 
3772a1cb98faSBarry Smith   Not Collective
3773552f7358SJed Brown 
3774552f7358SJed Brown   Input Parameters:
377560225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3776a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3777552f7358SJed Brown 
3778552f7358SJed Brown   Output Parameter:
37792c9a7b26SBarry Smith . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3780552f7358SJed Brown 
3781552f7358SJed Brown   Level: beginner
3782552f7358SJed Brown 
378360225df5SJacob Faibussowitsch   Fortran Notes:
37842c9a7b26SBarry Smith   `support` must be declared with
37852c9a7b26SBarry Smith .vb
37862c9a7b26SBarry Smith   PetscInt, pointer :: support(:)
37872c9a7b26SBarry Smith .ve
37882c9a7b26SBarry Smith 
3789a1cb98faSBarry Smith   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3790a1cb98faSBarry Smith   `DMPlexRestoreSupport()` is not needed/available in C.
37913813dfbdSMatthew G Knepley 
37921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3793552f7358SJed Brown @*/
3794d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3795d71ae5a4SJacob Faibussowitsch {
3796552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3797552f7358SJed Brown   PetscInt off;
3798552f7358SJed Brown 
3799552f7358SJed Brown   PetscFunctionBegin;
3800552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38014f572ea9SToby Isaac   PetscAssertPointer(support, 3);
38029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
38038e3a54c0SPierre Jolivet   *support = PetscSafePointerPlusOffset(mesh->supports, off);
38043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3805552f7358SJed Brown }
3806552f7358SJed Brown 
3807552f7358SJed Brown /*@
380892371b87SBarry 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
3809552f7358SJed Brown 
3810a1cb98faSBarry Smith   Not Collective
3811552f7358SJed Brown 
3812552f7358SJed Brown   Input Parameters:
381360225df5SJacob Faibussowitsch + dm      - The `DMPLEX`
3814a1cb98faSBarry Smith . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
38152c9a7b26SBarry Smith - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3816552f7358SJed Brown 
3817552f7358SJed Brown   Level: beginner
3818552f7358SJed Brown 
3819a1cb98faSBarry Smith   Note:
3820a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3821a1cb98faSBarry Smith 
38221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3823552f7358SJed Brown @*/
3824d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3825d71ae5a4SJacob Faibussowitsch {
3826552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3827552f7358SJed Brown   PetscInt pStart, pEnd;
3828552f7358SJed Brown   PetscInt dof, off, c;
3829552f7358SJed Brown 
3830552f7358SJed Brown   PetscFunctionBegin;
3831552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
38339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
38344f572ea9SToby Isaac   if (dof) PetscAssertPointer(support, 3);
38359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
383663a3b9bcSJacob 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);
3837552f7358SJed Brown   for (c = 0; c < dof; ++c) {
383863a3b9bcSJacob 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);
3839552f7358SJed Brown     mesh->supports[off + c] = support[c];
3840552f7358SJed Brown   }
38413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3842552f7358SJed Brown }
3843552f7358SJed Brown 
38447cd05799SMatthew G. Knepley /*@
3845eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
38467cd05799SMatthew G. Knepley 
3847a1cb98faSBarry Smith   Not Collective
38487cd05799SMatthew G. Knepley 
38497cd05799SMatthew G. Knepley   Input Parameters:
385060225df5SJacob Faibussowitsch + dm           - The `DMPLEX`
3851a1cb98faSBarry Smith . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
38527cd05799SMatthew G. Knepley . supportPos   - The local index in the cone where the point should be put
38537cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
38547cd05799SMatthew G. Knepley 
38557cd05799SMatthew G. Knepley   Level: beginner
38567cd05799SMatthew G. Knepley 
38571cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
38587cd05799SMatthew G. Knepley @*/
3859d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3860d71ae5a4SJacob Faibussowitsch {
3861552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3862552f7358SJed Brown   PetscInt pStart, pEnd;
3863552f7358SJed Brown   PetscInt dof, off;
3864552f7358SJed Brown 
3865552f7358SJed Brown   PetscFunctionBegin;
3866552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
38689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
38699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
387063a3b9bcSJacob 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);
387163a3b9bcSJacob 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);
387263a3b9bcSJacob 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);
3873552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
38743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3875552f7358SJed Brown }
3876552f7358SJed Brown 
3877b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3878d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3879d71ae5a4SJacob Faibussowitsch {
3880b5a892a1SMatthew G. Knepley   switch (ct) {
3881b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3882b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3883b5a892a1SMatthew G. Knepley     break;
3884b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3885b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3886b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3887b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3888b5a892a1SMatthew G. Knepley     break;
3889b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3890b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3891b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3892b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3893b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3894b5a892a1SMatthew G. Knepley     break;
3895d71ae5a4SJacob Faibussowitsch   default:
3896d71ae5a4SJacob Faibussowitsch     return o;
3897b5a892a1SMatthew G. Knepley   }
3898b5a892a1SMatthew G. Knepley   return o;
3899b5a892a1SMatthew G. Knepley }
3900b5a892a1SMatthew G. Knepley 
3901b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3902d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3903d71ae5a4SJacob Faibussowitsch {
3904b5a892a1SMatthew G. Knepley   switch (ct) {
3905b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3906b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3907b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3908b5a892a1SMatthew G. Knepley     break;
3909b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3910b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3911b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3912b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3913b5a892a1SMatthew G. Knepley     break;
3914b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3915b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3916b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3917b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3918b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3919b5a892a1SMatthew G. Knepley     break;
3920d71ae5a4SJacob Faibussowitsch   default:
3921d71ae5a4SJacob Faibussowitsch     return o;
3922b5a892a1SMatthew G. Knepley   }
3923b5a892a1SMatthew G. Knepley   return o;
3924b5a892a1SMatthew G. Knepley }
3925b5a892a1SMatthew G. Knepley 
3926b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3927d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3928d71ae5a4SJacob Faibussowitsch {
3929b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3930b5a892a1SMatthew G. Knepley 
3931b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
39329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3933b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3934b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3935b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3936b5a892a1SMatthew G. Knepley 
39379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
39389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
39399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3940b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3941b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3942b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3943b5a892a1SMatthew G. Knepley 
39449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3945b5a892a1SMatthew G. Knepley       switch (ct) {
3946b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
39479566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
39489566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3949b5a892a1SMatthew G. Knepley         break;
3950b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
39519566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
39529566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
39539566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3954b5a892a1SMatthew G. Knepley         break;
3955b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
39569566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
39579566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
39589566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
39599566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3960b5a892a1SMatthew G. Knepley         break;
3961d71ae5a4SJacob Faibussowitsch       default:
3962d71ae5a4SJacob Faibussowitsch         break;
3963b5a892a1SMatthew G. Knepley       }
3964b5a892a1SMatthew G. Knepley     }
3965b5a892a1SMatthew G. Knepley   }
39663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3967b5a892a1SMatthew G. Knepley }
3968b5a892a1SMatthew G. Knepley 
396909015e70SStefano Zampini static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
397009015e70SStefano Zampini {
397109015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
397209015e70SStefano Zampini 
397309015e70SStefano Zampini   PetscFunctionBeginHot;
397409015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
397509015e70SStefano Zampini     if (useCone) {
397609015e70SStefano Zampini       PetscCall(DMPlexGetConeSize(dm, p, size));
397709015e70SStefano Zampini       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
397809015e70SStefano Zampini     } else {
397909015e70SStefano Zampini       PetscCall(DMPlexGetSupportSize(dm, p, size));
398009015e70SStefano Zampini       PetscCall(DMPlexGetSupport(dm, p, arr));
398109015e70SStefano Zampini     }
398209015e70SStefano Zampini   } else {
398309015e70SStefano Zampini     if (useCone) {
398409015e70SStefano Zampini       const PetscSection s   = mesh->coneSection;
398509015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
398609015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
398709015e70SStefano Zampini 
398809015e70SStefano Zampini       *size = s->atlasDof[ps];
398909015e70SStefano Zampini       *arr  = mesh->cones + off;
399009015e70SStefano Zampini       *ornt = mesh->coneOrientations + off;
399109015e70SStefano Zampini     } else {
399209015e70SStefano Zampini       const PetscSection s   = mesh->supportSection;
399309015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
399409015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
399509015e70SStefano Zampini 
399609015e70SStefano Zampini       *size = s->atlasDof[ps];
399709015e70SStefano Zampini       *arr  = mesh->supports + off;
399809015e70SStefano Zampini     }
399909015e70SStefano Zampini   }
400009015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
400109015e70SStefano Zampini }
400209015e70SStefano Zampini 
400309015e70SStefano Zampini static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
400409015e70SStefano Zampini {
400509015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
400609015e70SStefano Zampini 
400709015e70SStefano Zampini   PetscFunctionBeginHot;
400809015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
400909015e70SStefano Zampini     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
401009015e70SStefano Zampini   }
401109015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
401209015e70SStefano Zampini }
401309015e70SStefano Zampini 
4014d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4015d71ae5a4SJacob Faibussowitsch {
4016b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
4017b5a892a1SMatthew G. Knepley   PetscInt       *closure;
4018b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
4019b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
4020b5a892a1SMatthew G. Knepley 
4021b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4022b5a892a1SMatthew G. Knepley   if (ornt) {
40239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
4024476787b7SMatthew 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;
4025b5a892a1SMatthew G. Knepley   }
4026b5a892a1SMatthew G. Knepley   if (*points) {
4027b5a892a1SMatthew G. Knepley     closure = *points;
4028b5a892a1SMatthew G. Knepley   } else {
4029b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
40309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
40319566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
4032b5a892a1SMatthew G. Knepley   }
403309015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
4034b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
4035b5a892a1SMatthew G. Knepley     closure[off++] = p;
4036b5a892a1SMatthew G. Knepley     closure[off++] = 0;
4037b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4038b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
4039b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
4040b5a892a1SMatthew G. Knepley     }
4041b5a892a1SMatthew G. Knepley   } else {
404285036b15SMatthew G. Knepley     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);
4043b5a892a1SMatthew G. Knepley 
4044b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
4045b5a892a1SMatthew G. Knepley     closure[off++] = p;
4046b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
4047b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4048b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
4049b5a892a1SMatthew G. Knepley 
40509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
4051b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
4052b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
4053b5a892a1SMatthew G. Knepley     }
4054b5a892a1SMatthew G. Knepley   }
405509015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
4056b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
4057b5a892a1SMatthew G. Knepley   if (points) *points = closure;
40583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4059b5a892a1SMatthew G. Knepley }
4060b5a892a1SMatthew G. Knepley 
4061d5b43468SJose E. Roman /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
4062d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
4063d71ae5a4SJacob Faibussowitsch {
406485036b15SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
4065b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
4066b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
4067b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
4068b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
4069b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
4070b5a892a1SMatthew G. Knepley 
4071b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
40729566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
407309015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
40749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4075b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
4076b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
4077b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
40789371c9d4SSatish Balay   if (*points) {
40799371c9d4SSatish Balay     pts = *points;
40809371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
4081b5a892a1SMatthew G. Knepley   c        = 0;
4082b5a892a1SMatthew G. Knepley   pts[c++] = point;
4083b5a892a1SMatthew G. Knepley   pts[c++] = o;
40849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
40859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
40869371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
40879371c9d4SSatish Balay     pts[c++] = closure[cl];
40889371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
40899371c9d4SSatish Balay   }
40909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
40919371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
40929371c9d4SSatish Balay     pts[c++] = closure[cl];
40939371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
40949371c9d4SSatish Balay   }
40959566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
4096b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
40979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
4098b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
4099b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
4100b5a892a1SMatthew G. Knepley   }
410109015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
4102b5a892a1SMatthew G. Knepley   if (dim >= 3) {
4103b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
4104b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
4105b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
4106b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
4107b5a892a1SMatthew G. Knepley 
41089566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
410985036b15SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
411009015e70SStefano Zampini       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4111b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
4112b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
4113b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
4114b5a892a1SMatthew G. Knepley 
41159371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
41169371c9d4SSatish Balay           if (pts[i] == cp) break;
4117b5a892a1SMatthew G. Knepley         if (i == c) {
41189566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
4119b5a892a1SMatthew G. Knepley           pts[c++] = cp;
4120b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
4121b5a892a1SMatthew G. Knepley         }
4122b5a892a1SMatthew G. Knepley       }
412309015e70SStefano Zampini       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4124b5a892a1SMatthew G. Knepley     }
4125b5a892a1SMatthew G. Knepley   }
4126b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
4127b5a892a1SMatthew G. Knepley   *points    = pts;
41283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4129b5a892a1SMatthew G. Knepley }
4130b5a892a1SMatthew G. Knepley 
4131d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4132d71ae5a4SJacob Faibussowitsch {
4133b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
4134b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
4135b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
4136b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
4137b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
4138b5a892a1SMatthew G. Knepley 
4139b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
41409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
4141b5a892a1SMatthew G. Knepley   if (depth == 1) {
41429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
41433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4144b5a892a1SMatthew G. Knepley   }
41459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
4146476787b7SMatthew 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;
4147c306944fSJed Brown   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
41489566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
41493ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4150b5a892a1SMatthew G. Knepley   }
41519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4152b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
4153b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
4154b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
41559566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
41569371c9d4SSatish Balay   if (*points) {
41579371c9d4SSatish Balay     closure = *points;
41589371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
4159b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
4160b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
4161b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
4162b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
4163b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
4164b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
4165b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
4166b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
4167b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
4168b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
416985036b15SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
417009015e70SStefano Zampini     const PetscInt      *tmp, *tmpO = NULL;
4171b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
4172b5a892a1SMatthew G. Knepley 
4173b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
417485036b15SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
417563a3b9bcSJacob 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);
4176b5a892a1SMatthew G. Knepley     }
417709015e70SStefano Zampini     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4178b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4179b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4180b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4181b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
41829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4183b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4184b5a892a1SMatthew G. Knepley       PetscInt       c;
4185b5a892a1SMatthew G. Knepley 
4186b5a892a1SMatthew G. Knepley       /* Check for duplicate */
4187b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
4188b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
4189b5a892a1SMatthew G. Knepley       }
4190b5a892a1SMatthew G. Knepley       if (c == closureSize) {
4191b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
4192b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
4193b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
4194b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
4195b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
4196b5a892a1SMatthew G. Knepley       }
4197b5a892a1SMatthew G. Knepley     }
419809015e70SStefano Zampini     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4199b5a892a1SMatthew G. Knepley   }
42009566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4201b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
4202b5a892a1SMatthew G. Knepley   if (points) *points = closure;
42033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4204b5a892a1SMatthew G. Knepley }
4205b5a892a1SMatthew G. Knepley 
4206552f7358SJed Brown /*@C
4207eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
4208552f7358SJed Brown 
4209a1cb98faSBarry Smith   Not Collective
4210552f7358SJed Brown 
4211552f7358SJed Brown   Input Parameters:
4212a1cb98faSBarry Smith + dm      - The `DMPLEX`
4213b5a892a1SMatthew G. Knepley . p       - The mesh point
4214*7d8e5ce9SJames Wright - useCone - `PETSC_TRUE` for the closure, otherwise return the support
4215552f7358SJed Brown 
42166b867d5aSJose E. Roman   Input/Output Parameter:
42176b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
42182c9a7b26SBarry Smith            if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`,
42192c9a7b26SBarry Smith            otherwise the provided array is used to hold the values
42206b867d5aSJose E. Roman 
42216b867d5aSJose E. Roman   Output Parameter:
42222c9a7b26SBarry Smith . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints`
4223552f7358SJed Brown 
4224a1cb98faSBarry Smith   Level: beginner
4225a1cb98faSBarry Smith 
4226552f7358SJed Brown   Note:
422720f4b53cSBarry Smith   If using internal storage (points is `NULL` on input), each call overwrites the last output.
4228552f7358SJed Brown 
422960225df5SJacob Faibussowitsch   Fortran Notes:
42302c9a7b26SBarry Smith   `points` must be declared with
42312c9a7b26SBarry Smith .vb
42322c9a7b26SBarry Smith   PetscInt, pointer :: points(:)
42332c9a7b26SBarry Smith .ve
42342c9a7b26SBarry Smith   and is always allocated by the function.
42352c9a7b26SBarry Smith 
4236feaf08eaSBarry Smith   Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed
42373813dfbdSMatthew G Knepley 
42381cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4239552f7358SJed Brown @*/
4240d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4241d71ae5a4SJacob Faibussowitsch {
4242b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4243552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42444f572ea9SToby Isaac   if (numPoints) PetscAssertPointer(numPoints, 4);
42454f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 5);
4246332e0eaaSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) {
4247332e0eaaSMatthew G. Knepley     PetscInt pStart, pEnd;
4248332e0eaaSMatthew G. Knepley     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4249332e0eaaSMatthew 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);
4250332e0eaaSMatthew G. Knepley   }
42519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
42523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42539bf0dad6SMatthew G. Knepley }
42549bf0dad6SMatthew G. Knepley 
4255552f7358SJed Brown /*@C
4256eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
4257552f7358SJed Brown 
4258a1cb98faSBarry Smith   Not Collective
4259552f7358SJed Brown 
4260552f7358SJed Brown   Input Parameters:
4261a1cb98faSBarry Smith + dm        - The `DMPLEX`
4262b5a892a1SMatthew G. Knepley . p         - The mesh point
4263a1cb98faSBarry Smith . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
426420f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4265b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
4266552f7358SJed Brown 
4267a1cb98faSBarry Smith   Level: beginner
4268a1cb98faSBarry Smith 
4269552f7358SJed Brown   Note:
427020f4b53cSBarry Smith   If not using internal storage (points is not `NULL` on input), this call is unnecessary
4271552f7358SJed Brown 
42721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4273552f7358SJed Brown @*/
4274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4275d71ae5a4SJacob Faibussowitsch {
4276b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4277552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42784ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
42799566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
42803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4281552f7358SJed Brown }
4282552f7358SJed Brown 
4283552f7358SJed Brown /*@
4284eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
4285552f7358SJed Brown 
4286a1cb98faSBarry Smith   Not Collective
4287552f7358SJed Brown 
4288552f7358SJed Brown   Input Parameter:
428960225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4290552f7358SJed Brown 
4291552f7358SJed Brown   Output Parameters:
4292552f7358SJed Brown + maxConeSize    - The maximum number of in-edges
4293552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
4294552f7358SJed Brown 
4295552f7358SJed Brown   Level: beginner
4296552f7358SJed Brown 
42971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4298552f7358SJed Brown @*/
4299ce78bad3SBarry Smith PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize)
4300d71ae5a4SJacob Faibussowitsch {
4301552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
4302552f7358SJed Brown 
4303552f7358SJed Brown   PetscFunctionBegin;
4304552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43051baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
43061baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
43073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4308552f7358SJed Brown }
4309552f7358SJed Brown 
4310d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
4311d71ae5a4SJacob Faibussowitsch {
4312552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
43136302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
4314552f7358SJed Brown 
4315552f7358SJed Brown   PetscFunctionBegin;
4316552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43179566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
43189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
43199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
43209566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
43216302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
43226302a7fbSVaclav Hapla   if (maxSupportSize) {
43239566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
43249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
43259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
4326552f7358SJed Brown   }
43273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4328552f7358SJed Brown }
4329552f7358SJed Brown 
4330d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4331d71ae5a4SJacob Faibussowitsch {
4332552f7358SJed Brown   PetscFunctionBegin;
43339566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
4334dd072f5fSMatthew G. Knepley   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
4335ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
4336736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
433795602cf2SAlexis Marboeuf     PetscSF sfNatural;
4338f94b4a02SBlaise Bourdin 
43393dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
43409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
434195602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4342c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
4343f94b4a02SBlaise Bourdin   }
43443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4345552f7358SJed Brown }
4346552f7358SJed Brown 
4347d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4348d71ae5a4SJacob Faibussowitsch {
43493dcd263cSBlaise Bourdin   PetscInt i = 0;
43502adcc780SMatthew G. Knepley 
43512adcc780SMatthew G. Knepley   PetscFunctionBegin;
43529566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
43539566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4354c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
43553dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
43563dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
435795602cf2SAlexis Marboeuf       PetscSF sfNatural;
43583dcd263cSBlaise Bourdin 
43593dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
43609566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4361c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
436295602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4363c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
43643dcd263cSBlaise Bourdin       break;
43653dcd263cSBlaise Bourdin     }
43663dcd263cSBlaise Bourdin   }
43673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43682adcc780SMatthew G. Knepley }
43692adcc780SMatthew G. Knepley 
4370552f7358SJed Brown /*@
4371eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4372552f7358SJed Brown 
4373a1cb98faSBarry Smith   Not Collective
4374552f7358SJed Brown 
4375552f7358SJed Brown   Input Parameter:
437660225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4377552f7358SJed Brown 
4378552f7358SJed Brown   Level: beginner
4379552f7358SJed Brown 
4380a1cb98faSBarry Smith   Note:
4381a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetCone()`
4382a1cb98faSBarry Smith 
43831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4384552f7358SJed Brown @*/
4385d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
4386d71ae5a4SJacob Faibussowitsch {
4387552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4388552f7358SJed Brown   PetscInt *offsets;
4389552f7358SJed Brown   PetscInt  supportSize;
4390552f7358SJed Brown   PetscInt  pStart, pEnd, p;
4391552f7358SJed Brown 
4392552f7358SJed Brown   PetscFunctionBegin;
4393552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
439428b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
43959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4396552f7358SJed Brown   /* Calculate support sizes */
43979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4398552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4399552f7358SJed Brown     PetscInt dof, off, c;
4400552f7358SJed Brown 
44019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
44029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
440348a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4404552f7358SJed Brown   }
44059566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
4406552f7358SJed Brown   /* Calculate supports */
44079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
44089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
44099566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4410552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4411552f7358SJed Brown     PetscInt dof, off, c;
4412552f7358SJed Brown 
44139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
44149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4415552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
4416552f7358SJed Brown       const PetscInt q = mesh->cones[c];
4417552f7358SJed Brown       PetscInt       offS;
4418552f7358SJed Brown 
44199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
44200d644c17SKarl Rupp 
4421552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
4422552f7358SJed Brown       ++offsets[q];
4423552f7358SJed Brown     }
4424552f7358SJed Brown   }
44259566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
44269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
44273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4428552f7358SJed Brown }
4429552f7358SJed Brown 
4430d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4431d71ae5a4SJacob Faibussowitsch {
4432277ea44aSLisandro Dalcin   IS stratumIS;
4433277ea44aSLisandro Dalcin 
4434277ea44aSLisandro Dalcin   PetscFunctionBegin;
44353ba16761SJacob Faibussowitsch   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
443676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4437277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4438277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
44399566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4440277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
44419566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
44429371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
44439371c9d4SSatish Balay         overlap = PETSC_TRUE;
44449371c9d4SSatish Balay         break;
44459371c9d4SSatish Balay       }
4446277ea44aSLisandro Dalcin     }
444763a3b9bcSJacob 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);
4448277ea44aSLisandro Dalcin   }
44499566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
44509566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
44519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
44523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4453277ea44aSLisandro Dalcin }
4454277ea44aSLisandro Dalcin 
4455e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4456e91fa0a1SMatthew G. Knepley {
4457e91fa0a1SMatthew G. Knepley   PetscInt *pMin, *pMax;
4458e91fa0a1SMatthew G. Knepley   PetscInt  pStart, pEnd;
44591690c2aeSBarry Smith   PetscInt  dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN;
4460e91fa0a1SMatthew G. Knepley 
4461e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4462e91fa0a1SMatthew G. Knepley   {
4463e91fa0a1SMatthew G. Knepley     DMLabel label2;
4464e91fa0a1SMatthew G. Knepley 
4465e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4466e91fa0a1SMatthew G. Knepley     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4467e91fa0a1SMatthew G. Knepley   }
4468e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4469e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4470e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4471e91fa0a1SMatthew G. Knepley 
4472e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4473e91fa0a1SMatthew G. Knepley     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4474e91fa0a1SMatthew G. Knepley     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4475e91fa0a1SMatthew G. Knepley   }
4476e91fa0a1SMatthew G. Knepley   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4477e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
44781690c2aeSBarry Smith     pMin[d] = PETSC_INT_MAX;
44791690c2aeSBarry Smith     pMax[d] = PETSC_INT_MIN;
4480e91fa0a1SMatthew G. Knepley   }
4481e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4482e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4483e91fa0a1SMatthew G. Knepley     PetscInt       d;
4484e91fa0a1SMatthew G. Knepley 
4485e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4486e91fa0a1SMatthew G. Knepley     d       = DMPolytopeTypeGetDim(ct);
4487e91fa0a1SMatthew G. Knepley     pMin[d] = PetscMin(p, pMin[d]);
4488e91fa0a1SMatthew G. Knepley     pMax[d] = PetscMax(p, pMax[d]);
4489e91fa0a1SMatthew G. Knepley   }
4490e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4491e91fa0a1SMatthew G. Knepley     if (pMin[d] > pMax[d]) continue;
4492e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4493e91fa0a1SMatthew G. Knepley   }
4494e91fa0a1SMatthew G. Knepley   PetscCall(PetscFree2(pMin, pMax));
4495e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4496e91fa0a1SMatthew G. Knepley }
4497e91fa0a1SMatthew G. Knepley 
4498e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4499e91fa0a1SMatthew G. Knepley {
4500e91fa0a1SMatthew G. Knepley   PetscInt pStart, pEnd;
4501e91fa0a1SMatthew G. Knepley   PetscInt numRoots = 0, numLeaves = 0;
4502e91fa0a1SMatthew G. Knepley 
4503e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4504e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4505e91fa0a1SMatthew G. Knepley   {
4506e91fa0a1SMatthew G. Knepley     /* Initialize roots and count leaves */
45071690c2aeSBarry Smith     PetscInt sMin = PETSC_INT_MAX;
45081690c2aeSBarry Smith     PetscInt sMax = PETSC_INT_MIN;
4509e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4510e91fa0a1SMatthew G. Knepley 
4511e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4512e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4513e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4514e91fa0a1SMatthew G. Knepley       if (!coneSize && supportSize) {
4515e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4516e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4517e91fa0a1SMatthew G. Knepley         ++numRoots;
4518e91fa0a1SMatthew G. Knepley       } else if (!supportSize && coneSize) {
4519e91fa0a1SMatthew G. Knepley         ++numLeaves;
4520e91fa0a1SMatthew G. Knepley       } else if (!supportSize && !coneSize) {
4521e91fa0a1SMatthew G. Knepley         /* Isolated points */
4522e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4523e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4524e91fa0a1SMatthew G. Knepley       }
4525e91fa0a1SMatthew G. Knepley     }
4526e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4527e91fa0a1SMatthew G. Knepley   }
4528e91fa0a1SMatthew G. Knepley 
4529e91fa0a1SMatthew G. Knepley   if (numRoots + numLeaves == (pEnd - pStart)) {
45301690c2aeSBarry Smith     PetscInt sMin = PETSC_INT_MAX;
45311690c2aeSBarry Smith     PetscInt sMax = PETSC_INT_MIN;
4532e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4533e91fa0a1SMatthew G. Knepley 
4534e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4535e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4536e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4537e91fa0a1SMatthew G. Knepley       if (!supportSize && coneSize) {
4538e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4539e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4540e91fa0a1SMatthew G. Knepley       }
4541e91fa0a1SMatthew G. Knepley     }
4542e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4543e91fa0a1SMatthew G. Knepley   } else {
4544e91fa0a1SMatthew G. Knepley     PetscInt level = 0;
4545e91fa0a1SMatthew G. Knepley     PetscInt qStart, qEnd;
4546e91fa0a1SMatthew G. Knepley 
4547e91fa0a1SMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4548e91fa0a1SMatthew G. Knepley     while (qEnd > qStart) {
45491690c2aeSBarry Smith       PetscInt sMin = PETSC_INT_MAX;
45501690c2aeSBarry Smith       PetscInt sMax = PETSC_INT_MIN;
4551e91fa0a1SMatthew G. Knepley 
4552e91fa0a1SMatthew G. Knepley       for (PetscInt q = qStart; q < qEnd; ++q) {
4553e91fa0a1SMatthew G. Knepley         const PetscInt *support;
4554e91fa0a1SMatthew G. Knepley         PetscInt        supportSize;
4555e91fa0a1SMatthew G. Knepley 
4556e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4557e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, q, &support));
4558e91fa0a1SMatthew G. Knepley         for (PetscInt s = 0; s < supportSize; ++s) {
4559e91fa0a1SMatthew G. Knepley           sMin = PetscMin(support[s], sMin);
4560e91fa0a1SMatthew G. Knepley           sMax = PetscMax(support[s], sMax);
4561e91fa0a1SMatthew G. Knepley         }
4562e91fa0a1SMatthew G. Knepley       }
4563e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetNumValues(label, &level));
4564e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4565e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4566e91fa0a1SMatthew G. Knepley     }
4567e91fa0a1SMatthew G. Knepley   }
4568e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4569e91fa0a1SMatthew G. Knepley }
4570e91fa0a1SMatthew G. Knepley 
4571552f7358SJed Brown /*@
4572a4e35b19SJacob Faibussowitsch   DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4573552f7358SJed Brown 
457420f4b53cSBarry Smith   Collective
4575552f7358SJed Brown 
4576552f7358SJed Brown   Input Parameter:
457760225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4578552f7358SJed Brown 
4579a1cb98faSBarry Smith   Level: beginner
4580552f7358SJed Brown 
4581552f7358SJed Brown   Notes:
4582a4e35b19SJacob Faibussowitsch   The strata group all points of the same grade, and this function calculates the strata. This
4583a4e35b19SJacob Faibussowitsch   grade can be seen as the height (or depth) of the point in the DAG.
4584a4e35b19SJacob Faibussowitsch 
4585a4e35b19SJacob Faibussowitsch   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4586a4e35b19SJacob Faibussowitsch   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4587a1cb98faSBarry Smith   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4588b1bb481bSMatthew 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
4589a1cb98faSBarry Smith   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4590a1cb98faSBarry Smith   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4591a1cb98faSBarry Smith   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4592552f7358SJed Brown 
4593b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4594b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4595b1bb481bSMatthew 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
4596b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4597a1cb98faSBarry Smith .vb
4598a1cb98faSBarry Smith   cone(c0) = {e0, v2}
4599a1cb98faSBarry Smith   cone(e0) = {v0, v1}
4600a1cb98faSBarry Smith .ve
4601a1cb98faSBarry Smith   If `DMPlexStratify()` is run on this mesh, it will give depths
4602a1cb98faSBarry Smith .vb
4603a1cb98faSBarry Smith    depth 0 = {v0, v1, v2}
4604a1cb98faSBarry Smith    depth 1 = {e0, c0}
4605a1cb98faSBarry Smith .ve
4606b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4607b1bb481bSMatthew Knepley 
4608a1cb98faSBarry Smith   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4609552f7358SJed Brown 
46101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4611552f7358SJed Brown @*/
4612d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4613d71ae5a4SJacob Faibussowitsch {
4614df0420ecSMatthew G. Knepley   DM_Plex  *mesh = (DM_Plex *)dm->data;
4615aa50250dSMatthew G. Knepley   DMLabel   label;
4616e91fa0a1SMatthew G. Knepley   PetscBool flg = PETSC_FALSE;
4617552f7358SJed Brown 
4618552f7358SJed Brown   PetscFunctionBegin;
4619552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
46209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4621277ea44aSLisandro Dalcin 
4622e91fa0a1SMatthew G. Knepley   // Create depth label
4623d28dd301SMatthew G. Knepley   PetscCall(DMRemoveLabel(dm, "depth", NULL));
46249566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
46259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4626277ea44aSLisandro Dalcin 
4627e91fa0a1SMatthew G. Knepley   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4628e91fa0a1SMatthew G. Knepley   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4629e91fa0a1SMatthew G. Knepley   else PetscCall(DMPlexStratify_Topological_Private(dm, label));
4630552f7358SJed Brown 
4631bf4602e4SToby Isaac   { /* just in case there is an empty process */
4632bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4633bf4602e4SToby Isaac 
46349566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
4635462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
463648a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4637bf4602e4SToby Isaac   }
46389566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
46399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
46403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4641552f7358SJed Brown }
4642552f7358SJed Brown 
4643d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4644d71ae5a4SJacob Faibussowitsch {
4645412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4646412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
46475e2c5519SMatthew G. Knepley   PetscBool      preferTensor;
4648ba2698f1SMatthew G. Knepley 
4649412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
46509566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
46519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
46529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
46535e2c5519SMatthew G. Knepley   PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor));
4654ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4655ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4656ba2698f1SMatthew G. Knepley     switch (pdepth) {
4657d71ae5a4SJacob Faibussowitsch     case 0:
4658d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4659d71ae5a4SJacob Faibussowitsch       break;
4660ba2698f1SMatthew G. Knepley     case 1:
4661ba2698f1SMatthew G. Knepley       switch (coneSize) {
4662d71ae5a4SJacob Faibussowitsch       case 2:
4663d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4664d71ae5a4SJacob Faibussowitsch         break;
4665d71ae5a4SJacob Faibussowitsch       case 3:
4666d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4667d71ae5a4SJacob Faibussowitsch         break;
4668ba2698f1SMatthew G. Knepley       case 4:
4669ba2698f1SMatthew G. Knepley         switch (dim) {
4670d71ae5a4SJacob Faibussowitsch         case 2:
4671d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4672d71ae5a4SJacob Faibussowitsch           break;
4673d71ae5a4SJacob Faibussowitsch         case 3:
4674d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4675d71ae5a4SJacob Faibussowitsch           break;
4676d71ae5a4SJacob Faibussowitsch         default:
4677d71ae5a4SJacob Faibussowitsch           break;
4678ba2698f1SMatthew G. Knepley         }
4679ba2698f1SMatthew G. Knepley         break;
4680d71ae5a4SJacob Faibussowitsch       case 5:
4681d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4682d71ae5a4SJacob Faibussowitsch         break;
4683d71ae5a4SJacob Faibussowitsch       case 6:
46845e2c5519SMatthew G. Knepley         ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM;
4685d71ae5a4SJacob Faibussowitsch         break;
4686d71ae5a4SJacob Faibussowitsch       case 8:
4687d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4688d71ae5a4SJacob Faibussowitsch         break;
4689d71ae5a4SJacob Faibussowitsch       default:
4690d71ae5a4SJacob Faibussowitsch         break;
4691ba2698f1SMatthew G. Knepley       }
4692ba2698f1SMatthew G. Knepley     }
4693ba2698f1SMatthew G. Knepley   } else {
4694ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4695ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4696ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4697ba2698f1SMatthew G. Knepley       switch (dim) {
4698ba2698f1SMatthew G. Knepley       case 1:
4699ba2698f1SMatthew G. Knepley         switch (coneSize) {
4700d71ae5a4SJacob Faibussowitsch         case 2:
4701d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4702d71ae5a4SJacob Faibussowitsch           break;
4703d71ae5a4SJacob Faibussowitsch         default:
4704d71ae5a4SJacob Faibussowitsch           break;
4705ba2698f1SMatthew G. Knepley         }
4706ba2698f1SMatthew G. Knepley         break;
4707ba2698f1SMatthew G. Knepley       case 2:
4708ba2698f1SMatthew G. Knepley         switch (coneSize) {
4709d71ae5a4SJacob Faibussowitsch         case 3:
4710d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4711d71ae5a4SJacob Faibussowitsch           break;
4712d71ae5a4SJacob Faibussowitsch         case 4:
4713d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4714d71ae5a4SJacob Faibussowitsch           break;
4715d71ae5a4SJacob Faibussowitsch         default:
4716d71ae5a4SJacob Faibussowitsch           break;
4717ba2698f1SMatthew G. Knepley         }
4718ba2698f1SMatthew G. Knepley         break;
4719ba2698f1SMatthew G. Knepley       case 3:
4720ba2698f1SMatthew G. Knepley         switch (coneSize) {
4721d71ae5a4SJacob Faibussowitsch         case 4:
4722d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4723d71ae5a4SJacob Faibussowitsch           break;
47249371c9d4SSatish Balay         case 5: {
4725da9060c4SMatthew G. Knepley           const PetscInt *cone;
4726da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4727da9060c4SMatthew G. Knepley 
47289566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
47299566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4730da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4731d71ae5a4SJacob Faibussowitsch           case 3:
47325e2c5519SMatthew G. Knepley             ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM;
4733d71ae5a4SJacob Faibussowitsch             break;
4734d71ae5a4SJacob Faibussowitsch           case 4:
4735d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4736d71ae5a4SJacob Faibussowitsch             break;
4737da9060c4SMatthew G. Knepley           }
47389371c9d4SSatish Balay         } break;
4739d71ae5a4SJacob Faibussowitsch         case 6:
4740d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4741d71ae5a4SJacob Faibussowitsch           break;
4742d71ae5a4SJacob Faibussowitsch         default:
4743d71ae5a4SJacob Faibussowitsch           break;
4744ba2698f1SMatthew G. Knepley         }
4745ba2698f1SMatthew G. Knepley         break;
4746d71ae5a4SJacob Faibussowitsch       default:
4747d71ae5a4SJacob Faibussowitsch         break;
4748ba2698f1SMatthew G. Knepley       }
4749ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4750ba2698f1SMatthew G. Knepley       switch (coneSize) {
4751d71ae5a4SJacob Faibussowitsch       case 2:
4752d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4753d71ae5a4SJacob Faibussowitsch         break;
4754d71ae5a4SJacob Faibussowitsch       case 3:
4755d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4756d71ae5a4SJacob Faibussowitsch         break;
4757d71ae5a4SJacob Faibussowitsch       case 4:
4758d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4759d71ae5a4SJacob Faibussowitsch         break;
4760d71ae5a4SJacob Faibussowitsch       default:
4761d71ae5a4SJacob Faibussowitsch         break;
4762ba2698f1SMatthew G. Knepley       }
4763ba2698f1SMatthew G. Knepley     }
4764ba2698f1SMatthew G. Knepley   }
4765412e9a14SMatthew G. Knepley   *pt = ct;
47663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4767ba2698f1SMatthew G. Knepley }
4768412e9a14SMatthew G. Knepley 
4769412e9a14SMatthew G. Knepley /*@
4770412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4771412e9a14SMatthew G. Knepley 
477220f4b53cSBarry Smith   Collective
4773412e9a14SMatthew G. Knepley 
4774412e9a14SMatthew G. Knepley   Input Parameter:
477560225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4776412e9a14SMatthew G. Knepley 
4777412e9a14SMatthew G. Knepley   Level: developer
4778412e9a14SMatthew G. Knepley 
4779a1cb98faSBarry Smith   Note:
4780a1cb98faSBarry Smith   This function is normally called automatically when a cell type is requested. It creates an
4781a1cb98faSBarry Smith   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4782a1cb98faSBarry Smith   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4783412e9a14SMatthew G. Knepley 
4784a1cb98faSBarry Smith   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4785a1cb98faSBarry Smith 
47861cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4787412e9a14SMatthew G. Knepley @*/
4788d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4789d71ae5a4SJacob Faibussowitsch {
4790412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4791412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4792412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4793412e9a14SMatthew G. Knepley 
4794412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4795412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4796412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
47979566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
47989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
47999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
480021027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
480121027e53SStefano Zampini   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4802412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4803327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4804412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4805412e9a14SMatthew G. Knepley 
48069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
48079566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4808841fc1b7SMatthew 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]);
48099566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
48106497c311SBarry Smith     mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
4811412e9a14SMatthew G. Knepley   }
48129566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
48139566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
48143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4815ba2698f1SMatthew G. Knepley }
4816ba2698f1SMatthew G. Knepley 
4817552f7358SJed Brown /*@C
4818552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4819552f7358SJed Brown 
4820552f7358SJed Brown   Not Collective
4821552f7358SJed Brown 
4822552f7358SJed Brown   Input Parameters:
4823a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4824552f7358SJed Brown . numPoints - The number of input points for the join
4825552f7358SJed Brown - points    - The input points
4826552f7358SJed Brown 
4827552f7358SJed Brown   Output Parameters:
4828552f7358SJed Brown + numCoveredPoints - The number of points in the join
4829552f7358SJed Brown - coveredPoints    - The points in the join
4830552f7358SJed Brown 
4831552f7358SJed Brown   Level: intermediate
4832552f7358SJed Brown 
4833a1cb98faSBarry Smith   Note:
4834a1cb98faSBarry Smith   Currently, this is restricted to a single level join
4835552f7358SJed Brown 
483660225df5SJacob Faibussowitsch   Fortran Notes:
48372c9a7b26SBarry Smith   `converedPoints` must be declared with
48382c9a7b26SBarry Smith .vb
48392c9a7b26SBarry Smith   PetscInt, pointer :: coveredPints(:)
48402c9a7b26SBarry Smith .ve
48412c9a7b26SBarry Smith 
48421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4843552f7358SJed Brown @*/
48445d83a8b1SBarry Smith PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4845d71ae5a4SJacob Faibussowitsch {
4846552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4847552f7358SJed Brown   PetscInt *join[2];
4848552f7358SJed Brown   PetscInt  joinSize, i = 0;
4849552f7358SJed Brown   PetscInt  dof, off, p, c, m;
48506302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4851552f7358SJed Brown 
4852552f7358SJed Brown   PetscFunctionBegin;
4853552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48544f572ea9SToby Isaac   PetscAssertPointer(points, 3);
48554f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
48564f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
48576302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
48586302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
48596302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4860552f7358SJed Brown   /* Copy in support of first point */
48619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
48629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4863ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4864552f7358SJed Brown   /* Check each successive support */
4865552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4866552f7358SJed Brown     PetscInt newJoinSize = 0;
4867552f7358SJed Brown 
48689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
48699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4870552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4871552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4872552f7358SJed Brown 
4873552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4874552f7358SJed Brown         if (point == join[i][m]) {
4875552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4876552f7358SJed Brown           break;
4877552f7358SJed Brown         }
4878552f7358SJed Brown       }
4879552f7358SJed Brown     }
4880552f7358SJed Brown     joinSize = newJoinSize;
4881552f7358SJed Brown     i        = 1 - i;
4882552f7358SJed Brown   }
4883552f7358SJed Brown   *numCoveredPoints = joinSize;
4884552f7358SJed Brown   *coveredPoints    = join[i];
48856302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
48863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4887552f7358SJed Brown }
4888552f7358SJed Brown 
4889552f7358SJed Brown /*@C
48902c9a7b26SBarry Smith   DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()`
4891552f7358SJed Brown 
4892552f7358SJed Brown   Not Collective
4893552f7358SJed Brown 
4894552f7358SJed Brown   Input Parameters:
4895a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4896552f7358SJed Brown . numPoints - The number of input points for the join
4897552f7358SJed Brown - points    - The input points
4898552f7358SJed Brown 
4899552f7358SJed Brown   Output Parameters:
4900552f7358SJed Brown + numCoveredPoints - The number of points in the join
4901552f7358SJed Brown - coveredPoints    - The points in the join
4902552f7358SJed Brown 
4903552f7358SJed Brown   Level: intermediate
4904552f7358SJed Brown 
490560225df5SJacob Faibussowitsch   Fortran Notes:
4906feaf08eaSBarry Smith   `converedPoints` must be declared with
4907feaf08eaSBarry Smith .vb
4908feaf08eaSBarry Smith   PetscInt, pointer :: coveredPoints(:)
4909feaf08eaSBarry Smith .ve
4910feaf08eaSBarry Smith 
4911feaf08eaSBarry Smith   Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed
4912a1cb98faSBarry Smith 
49131cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4914552f7358SJed Brown @*/
49152c9a7b26SBarry Smith PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4916d71ae5a4SJacob Faibussowitsch {
4917552f7358SJed Brown   PetscFunctionBegin;
4918552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49194f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
49204f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
49214f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
49229566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4923d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
49243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4925552f7358SJed Brown }
4926552f7358SJed Brown 
4927552f7358SJed Brown /*@C
4928552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4929552f7358SJed Brown 
4930552f7358SJed Brown   Not Collective
4931552f7358SJed Brown 
4932552f7358SJed Brown   Input Parameters:
4933a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4934552f7358SJed Brown . numPoints - The number of input points for the join
49352c9a7b26SBarry Smith - points    - The input points, its length is `numPoints`
4936552f7358SJed Brown 
4937552f7358SJed Brown   Output Parameters:
4938552f7358SJed Brown + numCoveredPoints - The number of points in the join
49392c9a7b26SBarry Smith - coveredPoints    - The points in the join, its length is `numCoveredPoints`
4940552f7358SJed Brown 
4941552f7358SJed Brown   Level: intermediate
4942552f7358SJed Brown 
494360225df5SJacob Faibussowitsch   Fortran Notes:
49442c9a7b26SBarry Smith .vb
49452c9a7b26SBarry Smith   PetscInt, pointer :: coveredPints(:)
49462c9a7b26SBarry Smith .ve
49472c9a7b26SBarry Smith 
49481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4949552f7358SJed Brown @*/
49505d83a8b1SBarry Smith PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4951d71ae5a4SJacob Faibussowitsch {
4952552f7358SJed Brown   PetscInt *offsets, **closures;
4953552f7358SJed Brown   PetscInt *join[2];
4954552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
495524c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4956552f7358SJed Brown 
4957552f7358SJed Brown   PetscFunctionBegin;
4958552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49594f572ea9SToby Isaac   PetscAssertPointer(points, 3);
49604f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
49614f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4962552f7358SJed Brown 
49639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
49649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
49659566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
49666302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
496724c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
49689566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
49699566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4970552f7358SJed Brown 
4971552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4972552f7358SJed Brown     PetscInt closureSize;
4973552f7358SJed Brown 
49749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
49750d644c17SKarl Rupp 
4976552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4977552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4978552f7358SJed Brown       PetscInt pStart, pEnd, i;
4979552f7358SJed Brown 
49809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4981552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4982552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4983552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4984552f7358SJed Brown           break;
4985552f7358SJed Brown         }
4986552f7358SJed Brown       }
4987552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4988552f7358SJed Brown     }
498963a3b9bcSJacob 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);
4990552f7358SJed Brown   }
4991552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4992552f7358SJed Brown     PetscInt dof;
4993552f7358SJed Brown 
4994552f7358SJed Brown     /* Copy in support of first point */
4995552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4996ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4997552f7358SJed Brown     /* Check each successive cone */
4998552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4999552f7358SJed Brown       PetscInt newJoinSize = 0;
5000552f7358SJed Brown 
5001552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
5002552f7358SJed Brown       for (c = 0; c < dof; ++c) {
5003552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
5004552f7358SJed Brown 
5005552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
5006552f7358SJed Brown           if (point == join[i][m]) {
5007552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
5008552f7358SJed Brown             break;
5009552f7358SJed Brown           }
5010552f7358SJed Brown         }
5011552f7358SJed Brown       }
5012552f7358SJed Brown       joinSize = newJoinSize;
5013552f7358SJed Brown       i        = 1 - i;
5014552f7358SJed Brown     }
5015552f7358SJed Brown     if (joinSize) break;
5016552f7358SJed Brown   }
5017552f7358SJed Brown   *numCoveredPoints = joinSize;
5018552f7358SJed Brown   *coveredPoints    = join[i];
501948a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
50209566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
50219566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
50226302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
50233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5024552f7358SJed Brown }
5025552f7358SJed Brown 
5026552f7358SJed Brown /*@C
5027552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
5028552f7358SJed Brown 
5029552f7358SJed Brown   Not Collective
5030552f7358SJed Brown 
5031552f7358SJed Brown   Input Parameters:
5032a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5033552f7358SJed Brown . numPoints - The number of input points for the meet
50342c9a7b26SBarry Smith - points    - The input points, of length `numPoints`
5035552f7358SJed Brown 
5036552f7358SJed Brown   Output Parameters:
503760225df5SJacob Faibussowitsch + numCoveringPoints - The number of points in the meet
50382c9a7b26SBarry Smith - coveringPoints    - The points in the meet, of length `numCoveringPoints`
5039552f7358SJed Brown 
5040552f7358SJed Brown   Level: intermediate
5041552f7358SJed Brown 
5042a1cb98faSBarry Smith   Note:
5043a1cb98faSBarry Smith   Currently, this is restricted to a single level meet
5044552f7358SJed Brown 
5045feaf08eaSBarry Smith   Fortran Note:
50462c9a7b26SBarry Smith   `coveringPoints` must be declared with
50472c9a7b26SBarry Smith .vb
50482c9a7b26SBarry Smith   PetscInt, pointer :: coveringPoints(:)
50492c9a7b26SBarry Smith .ve
50502c9a7b26SBarry Smith 
50511cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5052552f7358SJed Brown @*/
50535d83a8b1SBarry Smith PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[])
5054d71ae5a4SJacob Faibussowitsch {
5055552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
5056552f7358SJed Brown   PetscInt *meet[2];
5057552f7358SJed Brown   PetscInt  meetSize, i = 0;
5058552f7358SJed Brown   PetscInt  dof, off, p, c, m;
50596302a7fbSVaclav Hapla   PetscInt  maxConeSize;
5060552f7358SJed Brown 
5061552f7358SJed Brown   PetscFunctionBegin;
5062552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50634f572ea9SToby Isaac   PetscAssertPointer(points, 3);
50644f572ea9SToby Isaac   PetscAssertPointer(numCoveringPoints, 4);
50654f572ea9SToby Isaac   PetscAssertPointer(coveringPoints, 5);
50666302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
50676302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
50686302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
5069552f7358SJed Brown   /* Copy in cone of first point */
50709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
50719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
5072ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
5073552f7358SJed Brown   /* Check each successive cone */
5074552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
5075552f7358SJed Brown     PetscInt newMeetSize = 0;
5076552f7358SJed Brown 
50779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
50789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
5079552f7358SJed Brown     for (c = 0; c < dof; ++c) {
5080552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
5081552f7358SJed Brown 
5082552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
5083552f7358SJed Brown         if (point == meet[i][m]) {
5084552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
5085552f7358SJed Brown           break;
5086552f7358SJed Brown         }
5087552f7358SJed Brown       }
5088552f7358SJed Brown     }
5089552f7358SJed Brown     meetSize = newMeetSize;
5090552f7358SJed Brown     i        = 1 - i;
5091552f7358SJed Brown   }
5092552f7358SJed Brown   *numCoveringPoints = meetSize;
5093552f7358SJed Brown   *coveringPoints    = meet[i];
50946302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
50953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5096552f7358SJed Brown }
5097552f7358SJed Brown 
5098552f7358SJed Brown /*@C
50992c9a7b26SBarry Smith   DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()`
5100552f7358SJed Brown 
5101552f7358SJed Brown   Not Collective
5102552f7358SJed Brown 
5103552f7358SJed Brown   Input Parameters:
5104a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5105552f7358SJed Brown . numPoints - The number of input points for the meet
5106552f7358SJed Brown - points    - The input points
5107552f7358SJed Brown 
5108552f7358SJed Brown   Output Parameters:
5109552f7358SJed Brown + numCoveredPoints - The number of points in the meet
5110552f7358SJed Brown - coveredPoints    - The points in the meet
5111552f7358SJed Brown 
5112552f7358SJed Brown   Level: intermediate
5113552f7358SJed Brown 
51141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
5115552f7358SJed Brown @*/
51165d83a8b1SBarry Smith PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5117d71ae5a4SJacob Faibussowitsch {
5118552f7358SJed Brown   PetscFunctionBegin;
5119552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51204f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
51214f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
51224f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
51239566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
5124d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
51253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5126552f7358SJed Brown }
5127552f7358SJed Brown 
5128552f7358SJed Brown /*@C
5129552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
5130552f7358SJed Brown 
5131552f7358SJed Brown   Not Collective
5132552f7358SJed Brown 
5133552f7358SJed Brown   Input Parameters:
5134a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5135552f7358SJed Brown . numPoints - The number of input points for the meet
51362c9a7b26SBarry Smith - points    - The input points, of length  `numPoints`
5137552f7358SJed Brown 
5138552f7358SJed Brown   Output Parameters:
5139552f7358SJed Brown + numCoveredPoints - The number of points in the meet
51402c9a7b26SBarry Smith - coveredPoints    - The points in the meet, of length  `numCoveredPoints`
5141552f7358SJed Brown 
5142552f7358SJed Brown   Level: intermediate
5143552f7358SJed Brown 
514460225df5SJacob Faibussowitsch   Fortran Notes:
5145feaf08eaSBarry Smith   `coveredPoints` must be declared with
51462c9a7b26SBarry Smith .vb
51472c9a7b26SBarry Smith   PetscInt, pointer :: coveredPoints(:)
51482c9a7b26SBarry Smith .ve
51492c9a7b26SBarry Smith 
51501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5151552f7358SJed Brown @*/
51525d83a8b1SBarry Smith PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5153d71ae5a4SJacob Faibussowitsch {
5154552f7358SJed Brown   PetscInt *offsets, **closures;
5155552f7358SJed Brown   PetscInt *meet[2];
5156552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
515724c766afSToby Isaac   PetscInt  p, h, c, m, mc;
5158552f7358SJed Brown 
5159552f7358SJed Brown   PetscFunctionBegin;
5160552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51614f572ea9SToby Isaac   PetscAssertPointer(points, 3);
51624f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
51634f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
5164552f7358SJed Brown 
51659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
51669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
51679566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
51686302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
516924c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
51709566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
51719566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
5172552f7358SJed Brown 
5173552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
5174552f7358SJed Brown     PetscInt closureSize;
5175552f7358SJed Brown 
51769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
51770d644c17SKarl Rupp 
5178552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
5179552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
5180552f7358SJed Brown       PetscInt pStart, pEnd, i;
5181552f7358SJed Brown 
51829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
5183552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
5184552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
5185552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
5186552f7358SJed Brown           break;
5187552f7358SJed Brown         }
5188552f7358SJed Brown       }
5189552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
5190552f7358SJed Brown     }
519163a3b9bcSJacob 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);
5192552f7358SJed Brown   }
5193552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
5194552f7358SJed Brown     PetscInt dof;
5195552f7358SJed Brown 
5196552f7358SJed Brown     /* Copy in cone of first point */
5197552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
5198ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
5199552f7358SJed Brown     /* Check each successive cone */
5200552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
5201552f7358SJed Brown       PetscInt newMeetSize = 0;
5202552f7358SJed Brown 
5203552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
5204552f7358SJed Brown       for (c = 0; c < dof; ++c) {
5205552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
5206552f7358SJed Brown 
5207552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
5208552f7358SJed Brown           if (point == meet[i][m]) {
5209552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
5210552f7358SJed Brown             break;
5211552f7358SJed Brown           }
5212552f7358SJed Brown         }
5213552f7358SJed Brown       }
5214552f7358SJed Brown       meetSize = newMeetSize;
5215552f7358SJed Brown       i        = 1 - i;
5216552f7358SJed Brown     }
5217552f7358SJed Brown     if (meetSize) break;
5218552f7358SJed Brown   }
5219552f7358SJed Brown   *numCoveredPoints = meetSize;
5220552f7358SJed Brown   *coveredPoints    = meet[i];
522148a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
52229566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
52239566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
52246302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
52253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5226552f7358SJed Brown }
5227552f7358SJed Brown 
5228cc4c1da9SBarry Smith /*@
5229a1cb98faSBarry Smith   DMPlexEqual - Determine if two `DM` have the same topology
52304e3744c5SMatthew G. Knepley 
52314e3744c5SMatthew G. Knepley   Not Collective
52324e3744c5SMatthew G. Knepley 
52334e3744c5SMatthew G. Knepley   Input Parameters:
5234a1cb98faSBarry Smith + dmA - A `DMPLEX` object
5235a1cb98faSBarry Smith - dmB - A `DMPLEX` object
52364e3744c5SMatthew G. Knepley 
52372fe279fdSBarry Smith   Output Parameter:
5238a1cb98faSBarry Smith . equal - `PETSC_TRUE` if the topologies are identical
52394e3744c5SMatthew G. Knepley 
52404e3744c5SMatthew G. Knepley   Level: intermediate
52414e3744c5SMatthew G. Knepley 
5242a1cb98faSBarry Smith   Note:
52433c7db156SBarry Smith   We are not solving graph isomorphism, so we do not permute.
52444e3744c5SMatthew G. Knepley 
52451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
52464e3744c5SMatthew G. Knepley @*/
5247d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5248d71ae5a4SJacob Faibussowitsch {
52494e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
52504e3744c5SMatthew G. Knepley 
52514e3744c5SMatthew G. Knepley   PetscFunctionBegin;
52524e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
52534e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
52544f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
52554e3744c5SMatthew G. Knepley 
52564e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
52579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
52589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
52593ba16761SJacob Faibussowitsch   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
52609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
52619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
52623ba16761SJacob Faibussowitsch   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
52634e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
52644e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
52654e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
52664e3744c5SMatthew G. Knepley 
52679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
52689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
52699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
52709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
52719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
52729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
52733ba16761SJacob Faibussowitsch     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
52744e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
52753ba16761SJacob Faibussowitsch       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
52763ba16761SJacob Faibussowitsch       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
52774e3744c5SMatthew G. Knepley     }
52789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
52799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
52809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
52819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
52823ba16761SJacob Faibussowitsch     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
52834e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
52843ba16761SJacob Faibussowitsch       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
52854e3744c5SMatthew G. Knepley     }
52864e3744c5SMatthew G. Knepley   }
52874e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
52883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52894e3744c5SMatthew G. Knepley }
52904e3744c5SMatthew G. Knepley 
5291cc4c1da9SBarry Smith /*@
52927cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
52937cd05799SMatthew G. Knepley 
52947cd05799SMatthew G. Knepley   Not Collective
52957cd05799SMatthew G. Knepley 
52967cd05799SMatthew G. Knepley   Input Parameters:
5297a1cb98faSBarry Smith + dm         - The `DMPLEX`
52987cd05799SMatthew G. Knepley . cellDim    - The cell dimension
52997cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
53007cd05799SMatthew G. Knepley 
53012fe279fdSBarry Smith   Output Parameter:
53027cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
53037cd05799SMatthew G. Knepley 
53047cd05799SMatthew G. Knepley   Level: developer
53057cd05799SMatthew G. Knepley 
5306a1cb98faSBarry Smith   Note:
53077cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
53087cd05799SMatthew G. Knepley 
53091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
53107cd05799SMatthew G. Knepley @*/
5311d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5312d71ae5a4SJacob Faibussowitsch {
531382f516ccSBarry Smith   MPI_Comm comm;
5314552f7358SJed Brown 
5315552f7358SJed Brown   PetscFunctionBegin;
53169566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
53174f572ea9SToby Isaac   PetscAssertPointer(numFaceVertices, 4);
5318552f7358SJed Brown   switch (cellDim) {
5319d71ae5a4SJacob Faibussowitsch   case 0:
5320d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
5321d71ae5a4SJacob Faibussowitsch     break;
5322d71ae5a4SJacob Faibussowitsch   case 1:
5323d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
5324d71ae5a4SJacob Faibussowitsch     break;
5325552f7358SJed Brown   case 2:
5326552f7358SJed Brown     switch (numCorners) {
532719436ca2SJed Brown     case 3:                 /* triangle */
532819436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5329552f7358SJed Brown       break;
533019436ca2SJed Brown     case 4:                 /* quadrilateral */
533119436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5332552f7358SJed Brown       break;
533319436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
533419436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5335552f7358SJed Brown       break;
533619436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
533719436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5338552f7358SJed Brown       break;
5339d71ae5a4SJacob Faibussowitsch     default:
5340d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5341552f7358SJed Brown     }
5342552f7358SJed Brown     break;
5343552f7358SJed Brown   case 3:
5344552f7358SJed Brown     switch (numCorners) {
534519436ca2SJed Brown     case 4:                 /* tetradehdron */
534619436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
5347552f7358SJed Brown       break;
534819436ca2SJed Brown     case 6:                 /* tet cohesive cells */
534919436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5350552f7358SJed Brown       break;
535119436ca2SJed Brown     case 8:                 /* hexahedron */
535219436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5353552f7358SJed Brown       break;
535419436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
535519436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5356552f7358SJed Brown       break;
535719436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
535819436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5359552f7358SJed Brown       break;
536019436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
536119436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5362552f7358SJed Brown       break;
536319436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
536419436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5365552f7358SJed Brown       break;
536619436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
536719436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
5368552f7358SJed Brown       break;
5369d71ae5a4SJacob Faibussowitsch     default:
5370d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5371552f7358SJed Brown     }
5372552f7358SJed Brown     break;
5373d71ae5a4SJacob Faibussowitsch   default:
5374d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5375552f7358SJed Brown   }
53763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5377552f7358SJed Brown }
5378552f7358SJed Brown 
5379552f7358SJed Brown /*@
5380a1cb98faSBarry Smith   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
5381552f7358SJed Brown 
5382552f7358SJed Brown   Not Collective
5383552f7358SJed Brown 
5384aa50250dSMatthew G. Knepley   Input Parameter:
5385a1cb98faSBarry Smith . dm - The `DMPLEX` object
5386552f7358SJed Brown 
5387aa50250dSMatthew G. Knepley   Output Parameter:
5388a1cb98faSBarry Smith . depthLabel - The `DMLabel` recording point depth
5389552f7358SJed Brown 
5390552f7358SJed Brown   Level: developer
5391552f7358SJed Brown 
53921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5393aa50250dSMatthew G. Knepley @*/
5394d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5395d71ae5a4SJacob Faibussowitsch {
5396aa50250dSMatthew G. Knepley   PetscFunctionBegin;
5397aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53984f572ea9SToby Isaac   PetscAssertPointer(depthLabel, 2);
5399c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
54003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5401aa50250dSMatthew G. Knepley }
5402aa50250dSMatthew G. Knepley 
5403aa50250dSMatthew G. Knepley /*@
5404aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5405aa50250dSMatthew G. Knepley 
5406aa50250dSMatthew G. Knepley   Not Collective
5407aa50250dSMatthew G. Knepley 
5408aa50250dSMatthew G. Knepley   Input Parameter:
5409a1cb98faSBarry Smith . dm - The `DMPLEX` object
5410aa50250dSMatthew G. Knepley 
5411aa50250dSMatthew G. Knepley   Output Parameter:
5412aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
5413aa50250dSMatthew G. Knepley 
5414aa50250dSMatthew G. Knepley   Level: developer
5415552f7358SJed Brown 
5416b1bb481bSMatthew Knepley   Notes:
5417a1cb98faSBarry Smith   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
5418a1cb98faSBarry Smith 
5419a1cb98faSBarry Smith   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
5420a1cb98faSBarry Smith 
5421dc287ab2SVaclav Hapla   An empty mesh gives -1.
5422b1bb481bSMatthew Knepley 
54231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5424552f7358SJed Brown @*/
5425d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5426d71ae5a4SJacob Faibussowitsch {
54279f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5428aa50250dSMatthew G. Knepley   DMLabel  label;
5429452349dbSMatthew G. Knepley   PetscInt d = -1;
5430552f7358SJed Brown 
5431552f7358SJed Brown   PetscFunctionBegin;
5432552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54334f572ea9SToby Isaac   PetscAssertPointer(depth, 2);
54349f4ada15SMatthew G. Knepley   if (mesh->tr) {
54359f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
54369f4ada15SMatthew G. Knepley   } else {
54379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
5438452349dbSMatthew G. Knepley     // Allow missing depths
5439452349dbSMatthew G. Knepley     if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d));
5440452349dbSMatthew G. Knepley     *depth = d;
54419f4ada15SMatthew G. Knepley   }
54423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5443552f7358SJed Brown }
5444552f7358SJed Brown 
5445552f7358SJed Brown /*@
544620f4b53cSBarry Smith   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5447552f7358SJed Brown 
5448552f7358SJed Brown   Not Collective
5449552f7358SJed Brown 
5450552f7358SJed Brown   Input Parameters:
5451a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5452570fa34dSVaclav Hapla - depth - The requested depth
5453552f7358SJed Brown 
5454552f7358SJed Brown   Output Parameters:
545520f4b53cSBarry Smith + start - The first point at this `depth`
545620f4b53cSBarry Smith - end   - One beyond the last point at this `depth`
5457552f7358SJed Brown 
5458552f7358SJed Brown   Level: developer
5459552f7358SJed Brown 
5460a1cb98faSBarry Smith   Notes:
5461a1cb98faSBarry Smith   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5462a1cb98faSBarry Smith   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5463a1cb98faSBarry Smith   higher dimension, e.g., "edges".
5464a1cb98faSBarry Smith 
54652827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5466552f7358SJed Brown @*/
5467ce78bad3SBarry Smith PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end)
5468d71ae5a4SJacob Faibussowitsch {
54699f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5470aa50250dSMatthew G. Knepley   DMLabel  label;
547163d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
5472552f7358SJed Brown 
5473552f7358SJed Brown   PetscFunctionBegin;
5474552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54759371c9d4SSatish Balay   if (start) {
54764f572ea9SToby Isaac     PetscAssertPointer(start, 3);
54779371c9d4SSatish Balay     *start = 0;
54789371c9d4SSatish Balay   }
54799371c9d4SSatish Balay   if (end) {
54804f572ea9SToby Isaac     PetscAssertPointer(end, 4);
54819371c9d4SSatish Balay     *end = 0;
54829371c9d4SSatish Balay   }
54839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
54843ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5485570fa34dSVaclav Hapla   if (depth < 0) {
548663d1a920SMatthew G. Knepley     if (start) *start = pStart;
548763d1a920SMatthew G. Knepley     if (end) *end = pEnd;
54883ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5489552f7358SJed Brown   }
54909f4ada15SMatthew G. Knepley   if (mesh->tr) {
54919f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
54929f4ada15SMatthew G. Knepley   } else {
54939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
549428b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5495570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
54969f4ada15SMatthew G. Knepley   }
54973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5498552f7358SJed Brown }
5499552f7358SJed Brown 
5500552f7358SJed Brown /*@
550120f4b53cSBarry Smith   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5502552f7358SJed Brown 
5503552f7358SJed Brown   Not Collective
5504552f7358SJed Brown 
5505552f7358SJed Brown   Input Parameters:
5506a1cb98faSBarry Smith + dm     - The `DMPLEX` object
5507570fa34dSVaclav Hapla - height - The requested height
5508552f7358SJed Brown 
5509552f7358SJed Brown   Output Parameters:
551020f4b53cSBarry Smith + start - The first point at this `height`
551120f4b53cSBarry Smith - end   - One beyond the last point at this `height`
5512552f7358SJed Brown 
5513552f7358SJed Brown   Level: developer
5514552f7358SJed Brown 
5515a1cb98faSBarry Smith   Notes:
5516a1cb98faSBarry Smith   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5517a1cb98faSBarry Smith   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5518a1cb98faSBarry Smith   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5519a1cb98faSBarry Smith 
55202827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5521552f7358SJed Brown @*/
5522ce78bad3SBarry Smith PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end)
5523d71ae5a4SJacob Faibussowitsch {
5524aa50250dSMatthew G. Knepley   DMLabel  label;
552563d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5526552f7358SJed Brown 
5527552f7358SJed Brown   PetscFunctionBegin;
5528552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55299371c9d4SSatish Balay   if (start) {
55304f572ea9SToby Isaac     PetscAssertPointer(start, 3);
55319371c9d4SSatish Balay     *start = 0;
55329371c9d4SSatish Balay   }
55339371c9d4SSatish Balay   if (end) {
55344f572ea9SToby Isaac     PetscAssertPointer(end, 4);
55359371c9d4SSatish Balay     *end = 0;
55369371c9d4SSatish Balay   }
55379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
55383ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5539570fa34dSVaclav Hapla   if (height < 0) {
554063d1a920SMatthew G. Knepley     if (start) *start = pStart;
554163d1a920SMatthew G. Knepley     if (end) *end = pEnd;
55423ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5543552f7358SJed Brown   }
55449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
554559e4dc13SStefano Zampini   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
554659e4dc13SStefano Zampini   else PetscCall(DMGetDimension(dm, &depth));
554759e4dc13SStefano Zampini   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
554859e4dc13SStefano Zampini   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
55493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5550552f7358SJed Brown }
5551552f7358SJed Brown 
5552ba2698f1SMatthew G. Knepley /*@
555320f4b53cSBarry Smith   DMPlexGetPointDepth - Get the `depth` of a given point
5554ba2698f1SMatthew G. Knepley 
5555ba2698f1SMatthew G. Knepley   Not Collective
5556ba2698f1SMatthew G. Knepley 
5557d8d19677SJose E. Roman   Input Parameters:
5558a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5559ba2698f1SMatthew G. Knepley - point - The point
5560ba2698f1SMatthew G. Knepley 
5561ba2698f1SMatthew G. Knepley   Output Parameter:
556220f4b53cSBarry Smith . depth - The depth of the `point`
5563ba2698f1SMatthew G. Knepley 
5564ba2698f1SMatthew G. Knepley   Level: intermediate
5565ba2698f1SMatthew G. Knepley 
55661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5567ba2698f1SMatthew G. Knepley @*/
5568d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5569d71ae5a4SJacob Faibussowitsch {
5570ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5571ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55724f572ea9SToby Isaac   PetscAssertPointer(depth, 3);
55739566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
55743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5575ba2698f1SMatthew G. Knepley }
5576ba2698f1SMatthew G. Knepley 
5577ba2698f1SMatthew G. Knepley /*@
557820f4b53cSBarry Smith   DMPlexGetPointHeight - Get the `height` of a given point
55790c0a32dcSVaclav Hapla 
55800c0a32dcSVaclav Hapla   Not Collective
55810c0a32dcSVaclav Hapla 
5582d8d19677SJose E. Roman   Input Parameters:
5583a1cb98faSBarry Smith + dm    - The `DMPLEX` object
55840c0a32dcSVaclav Hapla - point - The point
55850c0a32dcSVaclav Hapla 
55860c0a32dcSVaclav Hapla   Output Parameter:
558720f4b53cSBarry Smith . height - The height of the `point`
55880c0a32dcSVaclav Hapla 
55890c0a32dcSVaclav Hapla   Level: intermediate
55900c0a32dcSVaclav Hapla 
55911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
55920c0a32dcSVaclav Hapla @*/
5593d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5594d71ae5a4SJacob Faibussowitsch {
55950c0a32dcSVaclav Hapla   PetscInt n, pDepth;
55960c0a32dcSVaclav Hapla 
55970c0a32dcSVaclav Hapla   PetscFunctionBegin;
55980c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55994f572ea9SToby Isaac   PetscAssertPointer(height, 3);
56009566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
56019566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
56020c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
56033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56040c0a32dcSVaclav Hapla }
56050c0a32dcSVaclav Hapla 
56060c0a32dcSVaclav Hapla /*@
5607a1cb98faSBarry Smith   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5608ba2698f1SMatthew G. Knepley 
5609ba2698f1SMatthew G. Knepley   Not Collective
5610ba2698f1SMatthew G. Knepley 
5611ba2698f1SMatthew G. Knepley   Input Parameter:
5612a1cb98faSBarry Smith . dm - The `DMPLEX` object
5613ba2698f1SMatthew G. Knepley 
5614ba2698f1SMatthew G. Knepley   Output Parameter:
5615a1cb98faSBarry Smith . celltypeLabel - The `DMLabel` recording cell polytope type
5616412e9a14SMatthew G. Knepley 
5617ba2698f1SMatthew G. Knepley   Level: developer
5618ba2698f1SMatthew G. Knepley 
5619a1cb98faSBarry Smith   Note:
5620a1cb98faSBarry Smith   This function will trigger automatica computation of cell types. This can be disabled by calling
5621a1cb98faSBarry Smith   `DMCreateLabel`(dm, "celltype") beforehand.
5622a1cb98faSBarry Smith 
56231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5624ba2698f1SMatthew G. Knepley @*/
5625d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5626d71ae5a4SJacob Faibussowitsch {
5627ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5628ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56294f572ea9SToby Isaac   PetscAssertPointer(celltypeLabel, 2);
56309566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5631ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
56323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5633ba2698f1SMatthew G. Knepley }
5634ba2698f1SMatthew G. Knepley 
5635ba2698f1SMatthew G. Knepley /*@
5636ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5637ba2698f1SMatthew G. Knepley 
5638ba2698f1SMatthew G. Knepley   Not Collective
5639ba2698f1SMatthew G. Knepley 
5640d8d19677SJose E. Roman   Input Parameters:
5641a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5642ba2698f1SMatthew G. Knepley - cell - The cell
5643ba2698f1SMatthew G. Knepley 
5644ba2698f1SMatthew G. Knepley   Output Parameter:
5645ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5646ba2698f1SMatthew G. Knepley 
5647ba2698f1SMatthew G. Knepley   Level: intermediate
5648ba2698f1SMatthew G. Knepley 
56491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5650ba2698f1SMatthew G. Knepley @*/
5651d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5652d71ae5a4SJacob Faibussowitsch {
56539f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5654ba2698f1SMatthew G. Knepley   DMLabel  label;
5655ba2698f1SMatthew G. Knepley   PetscInt ct;
5656ba2698f1SMatthew G. Knepley 
5657ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5658ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56594f572ea9SToby Isaac   PetscAssertPointer(celltype, 3);
56609f4ada15SMatthew G. Knepley   if (mesh->tr) {
56619f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
56629f4ada15SMatthew G. Knepley   } else {
566321027e53SStefano Zampini     PetscInt pStart, pEnd;
566421027e53SStefano Zampini 
566521027e53SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
566621027e53SStefano Zampini     if (!mesh->cellTypes) { /* XXX remove? optimize? */
566721027e53SStefano Zampini       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5668f4a55318SMatthew G. Knepley       if (pEnd <= pStart) {
5669f4a55318SMatthew G. Knepley         *celltype = DM_POLYTOPE_UNKNOWN;
5670f4a55318SMatthew G. Knepley         PetscFunctionReturn(PETSC_SUCCESS);
5671f4a55318SMatthew G. Knepley       }
567221027e53SStefano Zampini       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
567321027e53SStefano Zampini       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
567421027e53SStefano Zampini       for (PetscInt p = pStart; p < pEnd; p++) {
567521027e53SStefano Zampini         PetscCall(DMLabelGetValue(label, p, &ct));
56766497c311SBarry Smith         mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
567721027e53SStefano Zampini       }
567821027e53SStefano Zampini     }
567921027e53SStefano Zampini     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
568021027e53SStefano Zampini     if (PetscDefined(USE_DEBUG)) {
56819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
56829566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, cell, &ct));
568363a3b9bcSJacob Faibussowitsch       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5684936381afSPierre Jolivet       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
568521027e53SStefano Zampini     }
56869f4ada15SMatthew G. Knepley   }
56873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5688ba2698f1SMatthew G. Knepley }
5689ba2698f1SMatthew G. Knepley 
5690412e9a14SMatthew G. Knepley /*@
5691412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5692412e9a14SMatthew G. Knepley 
5693412e9a14SMatthew G. Knepley   Not Collective
5694412e9a14SMatthew G. Knepley 
5695412e9a14SMatthew G. Knepley   Input Parameters:
5696a1cb98faSBarry Smith + dm       - The `DMPLEX` object
5697412e9a14SMatthew G. Knepley . cell     - The cell
5698412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5699412e9a14SMatthew G. Knepley 
5700a1cb98faSBarry Smith   Level: advanced
5701a1cb98faSBarry Smith 
5702a1cb98faSBarry Smith   Note:
5703a1cb98faSBarry Smith   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5704412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5705412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5706db485b19SStefano Zampini   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5707412e9a14SMatthew G. Knepley 
57081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5709412e9a14SMatthew G. Knepley @*/
5710d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5711d71ae5a4SJacob Faibussowitsch {
571221027e53SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
5713412e9a14SMatthew G. Knepley   DMLabel  label;
571421027e53SStefano Zampini   PetscInt pStart, pEnd;
5715412e9a14SMatthew G. Knepley 
5716412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5717412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
571821027e53SStefano Zampini   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
57199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
57209566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
572121027e53SStefano Zampini   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
57226497c311SBarry Smith   mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype;
57233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5724412e9a14SMatthew G. Knepley }
5725412e9a14SMatthew G. Knepley 
5726d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5727d71ae5a4SJacob Faibussowitsch {
5728c789d87fSToby Isaac   PetscSection section;
57293e922f36SToby Isaac   PetscInt     maxHeight;
5730dd4c3f67SMatthew G. Knepley   const char  *prefix;
5731552f7358SJed Brown 
5732552f7358SJed Brown   PetscFunctionBegin;
57339566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
5734dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5735dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5736dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
57379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
57389566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
57399566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
57409566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
57419566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
57428f4c458bSMatthew G. Knepley 
57439566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
57449566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5745dd4c3f67SMatthew G. Knepley   (*cdm)->cloneOpts = PETSC_TRUE;
5746dd4c3f67SMatthew G. Knepley   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
57473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5748552f7358SJed Brown }
5749552f7358SJed Brown 
575099acd26cSksagiyam PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm)
575199acd26cSksagiyam {
575299acd26cSksagiyam   DM           cgcdm;
575399acd26cSksagiyam   PetscSection section;
575499acd26cSksagiyam   const char  *prefix;
575599acd26cSksagiyam 
575699acd26cSksagiyam   PetscFunctionBegin;
575799acd26cSksagiyam   PetscCall(DMGetCoordinateDM(dm, &cgcdm));
575899acd26cSksagiyam   PetscCall(DMClone(cgcdm, cdm));
575999acd26cSksagiyam   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
576099acd26cSksagiyam   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
576199acd26cSksagiyam   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_"));
576299acd26cSksagiyam   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
576399acd26cSksagiyam   PetscCall(DMSetLocalSection(*cdm, section));
576499acd26cSksagiyam   PetscCall(PetscSectionDestroy(&section));
576599acd26cSksagiyam   PetscCall(DMSetNumFields(*cdm, 1));
576699acd26cSksagiyam   PetscCall(DMCreateDS(*cdm));
576799acd26cSksagiyam   (*cdm)->cloneOpts = PETSC_TRUE;
576899acd26cSksagiyam   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
576999acd26cSksagiyam   PetscFunctionReturn(PETSC_SUCCESS);
577099acd26cSksagiyam }
577199acd26cSksagiyam 
5772d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5773d71ae5a4SJacob Faibussowitsch {
57746858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
57756858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5776f19dbd58SToby Isaac 
5777f19dbd58SToby Isaac   PetscFunctionBegin;
5778f19dbd58SToby Isaac   *field = NULL;
57799566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
57809566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
57816858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
57826858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5783f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
57846858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
57856858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5786f19dbd58SToby Isaac   }
57873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5788f19dbd58SToby Isaac }
5789f19dbd58SToby Isaac 
5790cc4c1da9SBarry Smith /*@
57917cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
57927cd05799SMatthew G. Knepley 
57937cd05799SMatthew G. Knepley   Not Collective
57947cd05799SMatthew G. Knepley 
57952fe279fdSBarry Smith   Input Parameter:
5796a1cb98faSBarry Smith . dm - The `DMPLEX` object
57977cd05799SMatthew G. Knepley 
57987cd05799SMatthew G. Knepley   Output Parameter:
5799a1cb98faSBarry Smith . section - The `PetscSection` object
58007cd05799SMatthew G. Knepley 
58017cd05799SMatthew G. Knepley   Level: developer
58027cd05799SMatthew G. Knepley 
58031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
58047cd05799SMatthew G. Knepley @*/
5805d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5806d71ae5a4SJacob Faibussowitsch {
5807552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5808552f7358SJed Brown 
5809552f7358SJed Brown   PetscFunctionBegin;
5810552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5811552f7358SJed Brown   if (section) *section = mesh->coneSection;
58123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5813552f7358SJed Brown }
5814552f7358SJed Brown 
5815cc4c1da9SBarry Smith /*@
58167cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
58177cd05799SMatthew G. Knepley 
58187cd05799SMatthew G. Knepley   Not Collective
58197cd05799SMatthew G. Knepley 
58202fe279fdSBarry Smith   Input Parameter:
5821a1cb98faSBarry Smith . dm - The `DMPLEX` object
58227cd05799SMatthew G. Knepley 
58237cd05799SMatthew G. Knepley   Output Parameter:
5824a1cb98faSBarry Smith . section - The `PetscSection` object
58257cd05799SMatthew G. Knepley 
58267cd05799SMatthew G. Knepley   Level: developer
58277cd05799SMatthew G. Knepley 
58281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
58297cd05799SMatthew G. Knepley @*/
5830d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5831d71ae5a4SJacob Faibussowitsch {
58328cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
58338cb4d582SMatthew G. Knepley 
58348cb4d582SMatthew G. Knepley   PetscFunctionBegin;
58358cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58368cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
58373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58388cb4d582SMatthew G. Knepley }
58398cb4d582SMatthew G. Knepley 
58407cd05799SMatthew G. Knepley /*@C
58417cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
58427cd05799SMatthew G. Knepley 
58437cd05799SMatthew G. Knepley   Not Collective
58447cd05799SMatthew G. Knepley 
58452fe279fdSBarry Smith   Input Parameter:
5846a1cb98faSBarry Smith . dm - The `DMPLEX` object
58477cd05799SMatthew G. Knepley 
58487cd05799SMatthew G. Knepley   Output Parameter:
58497cd05799SMatthew G. Knepley . cones - The cone for each point
58507cd05799SMatthew G. Knepley 
58517cd05799SMatthew G. Knepley   Level: developer
58527cd05799SMatthew G. Knepley 
58531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
58547cd05799SMatthew G. Knepley @*/
5855d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5856d71ae5a4SJacob Faibussowitsch {
5857552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5858552f7358SJed Brown 
5859552f7358SJed Brown   PetscFunctionBegin;
5860552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5861552f7358SJed Brown   if (cones) *cones = mesh->cones;
58623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5863552f7358SJed Brown }
5864552f7358SJed Brown 
58657cd05799SMatthew G. Knepley /*@C
58667cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
58677cd05799SMatthew G. Knepley 
58687cd05799SMatthew G. Knepley   Not Collective
58697cd05799SMatthew G. Knepley 
58702fe279fdSBarry Smith   Input Parameter:
5871a1cb98faSBarry Smith . dm - The `DMPLEX` object
58727cd05799SMatthew G. Knepley 
58737cd05799SMatthew G. Knepley   Output Parameter:
5874b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
58757cd05799SMatthew G. Knepley 
58767cd05799SMatthew G. Knepley   Level: developer
58777cd05799SMatthew G. Knepley 
5878b5a892a1SMatthew G. Knepley   Notes:
58792c9a7b26SBarry Smith   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points
58802c9a7b26SBarry Smith   as returned by `DMPlexGetConeOrientation()`.
5881b5a892a1SMatthew G. Knepley 
5882a1cb98faSBarry Smith   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5883b5a892a1SMatthew G. Knepley 
58841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
58857cd05799SMatthew G. Knepley @*/
5886d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5887d71ae5a4SJacob Faibussowitsch {
5888552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5889552f7358SJed Brown 
5890552f7358SJed Brown   PetscFunctionBegin;
5891552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5892552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
58933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5894552f7358SJed Brown }
5895552f7358SJed Brown 
58964ee01570SBarry Smith /* FEM Support */
5897552f7358SJed Brown 
5898d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5899d2b2dc1eSMatthew G. Knepley {
5900d2b2dc1eSMatthew G. Knepley   PetscInt depth;
5901d2b2dc1eSMatthew G. Knepley 
5902d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
5903d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
5904d2b2dc1eSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5905d2b2dc1eSMatthew G. Knepley   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5906d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
5907d2b2dc1eSMatthew G. Knepley }
5908d2b2dc1eSMatthew G. Knepley 
59095962854dSMatthew G. Knepley PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
59105962854dSMatthew G. Knepley {
59115962854dSMatthew G. Knepley   PetscInt depth;
59125962854dSMatthew G. Knepley 
59135962854dSMatthew G. Knepley   PetscFunctionBegin;
59145962854dSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
59155962854dSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
59165962854dSMatthew G. Knepley   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
59175962854dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
59185962854dSMatthew G. Knepley }
59195962854dSMatthew G. Knepley 
59209e8305c2SJed Brown /*
59219e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
59229e8305c2SJed Brown  representing a line in the section.
59239e8305c2SJed Brown */
59245f82726aSMatthew G. Knepley static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5925d71ae5a4SJacob Faibussowitsch {
5926e327e467SRezgar Shakeri   PetscObject  obj;
5927e327e467SRezgar Shakeri   PetscClassId id;
5928e327e467SRezgar Shakeri   PetscFE      fe = NULL;
5929e327e467SRezgar Shakeri 
59309e8305c2SJed Brown   PetscFunctionBeginHot;
59319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5932e327e467SRezgar Shakeri   PetscCall(DMGetField(dm, field, NULL, &obj));
5933e327e467SRezgar Shakeri   PetscCall(PetscObjectGetClassId(obj, &id));
5934e327e467SRezgar Shakeri   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;
5935e327e467SRezgar Shakeri 
5936e327e467SRezgar Shakeri   if (!fe) {
5937e327e467SRezgar Shakeri     /* Assume the full interpolated mesh is in the chart; lines in particular */
59389e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
59399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
59409e8305c2SJed Brown     *k = *k / *Nc + 1;
5941e327e467SRezgar Shakeri   } else {
5942e327e467SRezgar Shakeri     PetscInt       dual_space_size, dim;
59435f82726aSMatthew G. Knepley     PetscDualSpace dsp;
59445f82726aSMatthew G. Knepley 
5945e327e467SRezgar Shakeri     PetscCall(DMGetDimension(dm, &dim));
59465f82726aSMatthew G. Knepley     PetscCall(PetscFEGetDualSpace(fe, &dsp));
59475f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5948e327e467SRezgar Shakeri     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
59495f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
59505f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
59515f82726aSMatthew G. Knepley   }
59525f82726aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
59535f82726aSMatthew G. Knepley }
59545f82726aSMatthew G. Knepley 
59555f82726aSMatthew G. Knepley static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
59565f82726aSMatthew G. Knepley {
59575f82726aSMatthew G. Knepley   PetscFunctionBeginHot;
59585f82726aSMatthew G. Knepley   if (tensor) {
59595f82726aSMatthew G. Knepley     *dof = PetscPowInt(k + 1, dim);
59605f82726aSMatthew G. Knepley   } else {
59615f82726aSMatthew G. Knepley     switch (dim) {
59625f82726aSMatthew G. Knepley     case 1:
59635f82726aSMatthew G. Knepley       *dof = k + 1;
59645f82726aSMatthew G. Knepley       break;
59655f82726aSMatthew G. Knepley     case 2:
59665f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2)) / 2;
59675f82726aSMatthew G. Knepley       break;
59685f82726aSMatthew G. Knepley     case 3:
59695f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
59705f82726aSMatthew G. Knepley       break;
59715f82726aSMatthew G. Knepley     default:
59725f82726aSMatthew G. Knepley       *dof = 0;
59735f82726aSMatthew G. Knepley     }
59749e8305c2SJed Brown   }
59753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59769e8305c2SJed Brown }
59779e8305c2SJed Brown 
5978a4355906SMatthew Knepley /*@
5979bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5980bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
598120f4b53cSBarry Smith   section provided (or the section of the `DM`).
5982a4355906SMatthew Knepley 
5983a4355906SMatthew Knepley   Input Parameters:
598420f4b53cSBarry Smith + dm      - The `DM`
598520f4b53cSBarry Smith . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
598620f4b53cSBarry Smith - section - The `PetscSection` to reorder, or `NULL` for the default section
5987a4355906SMatthew Knepley 
5988bc1eb3faSJed Brown   Example:
5989bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5990bc1eb3faSJed Brown .vb
5991bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5992bc1eb3faSJed Brown 
5993bc1eb3faSJed Brown   v4 -- e6 -- v3
5994bc1eb3faSJed Brown   |           |
5995bc1eb3faSJed Brown   e7    c0    e8
5996bc1eb3faSJed Brown   |           |
5997bc1eb3faSJed Brown   v1 -- e5 -- v2
5998bc1eb3faSJed Brown .ve
5999bc1eb3faSJed Brown 
6000bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
6001bc1eb3faSJed Brown   dofs in the order of points, e.g.,
6002bc1eb3faSJed Brown .vb
6003bc1eb3faSJed Brown     c0 -> [0,1,2,3]
6004bc1eb3faSJed Brown     v1 -> [4]
6005bc1eb3faSJed Brown     ...
6006bc1eb3faSJed Brown     e5 -> [8, 9]
6007bc1eb3faSJed Brown .ve
6008bc1eb3faSJed Brown 
6009bc1eb3faSJed Brown   which corresponds to the dofs
6010bc1eb3faSJed Brown .vb
6011bc1eb3faSJed Brown     6   10  11  7
6012bc1eb3faSJed Brown     13  2   3   15
6013bc1eb3faSJed Brown     12  0   1   14
6014bc1eb3faSJed Brown     4   8   9   5
6015bc1eb3faSJed Brown .ve
6016bc1eb3faSJed Brown 
6017bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
6018bc1eb3faSJed Brown .vb
6019bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
6020bc1eb3faSJed Brown .ve
6021bc1eb3faSJed Brown 
6022bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
6023bc1eb3faSJed Brown .vb
6024bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
6025bc1eb3faSJed Brown .ve
6026bc1eb3faSJed Brown 
6027a4355906SMatthew Knepley   Level: developer
6028a4355906SMatthew Knepley 
6029da9ac489SAlbert Cowie   Notes:
6030a1cb98faSBarry Smith   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
6031a1cb98faSBarry Smith   degree of the basis.
6032a1cb98faSBarry Smith 
6033da9ac489SAlbert Cowie   This is required to run with libCEED.
6034da9ac489SAlbert Cowie 
60351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
6036a4355906SMatthew Knepley @*/
6037d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
6038d71ae5a4SJacob Faibussowitsch {
60397391a63aSMatthew G. Knepley   DMLabel   label;
6040bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
60415f82726aSMatthew G. Knepley   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;
60423194fc30SMatthew G. Knepley 
60433194fc30SMatthew G. Knepley   PetscFunctionBegin;
60449566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
60453ba16761SJacob Faibussowitsch   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
6046a433471fSStefano Zampini   if (point < 0) {
6047a433471fSStefano Zampini     PetscInt sStart, sEnd;
6048a433471fSStefano Zampini 
60499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
6050a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
6051a433471fSStefano Zampini   }
60529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
60539566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
60549566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
60559371c9d4SSatish Balay   if (depth == 1) {
60569371c9d4SSatish Balay     eStart = point;
60579371c9d4SSatish Balay   } else if (depth == dim) {
60587391a63aSMatthew G. Knepley     const PetscInt *cone;
60597391a63aSMatthew G. Knepley 
60609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
6061d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
6062d4e6627bSStefano Zampini     else if (dim == 3) {
6063d4e6627bSStefano Zampini       const PetscInt *cone2;
60649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
6065d4e6627bSStefano Zampini       eStart = cone2[0];
606663a3b9bcSJacob 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);
606763a3b9bcSJacob 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);
6068e327e467SRezgar Shakeri 
60699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
6070bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
6071bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
6072bb197d40SJed Brown     PetscInt *perm;
6073bb197d40SJed Brown 
60743194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
60755f82726aSMatthew G. Knepley       PetscInt dof;
60765f82726aSMatthew G. Knepley 
60775f82726aSMatthew G. Knepley       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
60785f82726aSMatthew 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);
60795f82726aSMatthew G. Knepley       if (!continuous && d < dim) continue;
60805f82726aSMatthew G. Knepley       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
60815f82726aSMatthew G. Knepley       size += dof * Nc;
60823194fc30SMatthew G. Knepley     }
60839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
60843194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
6085bb197d40SJed Brown       switch (d) {
6086babf31e0SJed Brown       case 1:
60875f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
60885f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
6089babf31e0SJed Brown         /*
6090babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
6091babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
6092babf31e0SJed Brown          */
6093e327e467SRezgar Shakeri         if (continuous) {
6094babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
60959371c9d4SSatish Balay           for (i = 0; i < k - 1; i++)
60969371c9d4SSatish Balay             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
6097babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
6098babf31e0SJed Brown           foffset = offset;
6099e327e467SRezgar Shakeri         } else {
61005f82726aSMatthew G. Knepley           PetscInt dof;
61015f82726aSMatthew G. Knepley 
61025f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
61035f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
61045f82726aSMatthew G. Knepley           foffset = offset;
6105e327e467SRezgar Shakeri         }
6106babf31e0SJed Brown         break;
610789eabcffSMatthew G. Knepley       case 2:
61083194fc30SMatthew 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} */
61095f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
61105f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
61113194fc30SMatthew G. Knepley         /* The SEM order is
61123194fc30SMatthew G. Knepley 
61133194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
611489eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
61153194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
61163194fc30SMatthew G. Knepley          */
6117e327e467SRezgar Shakeri         if (continuous) {
61183194fc30SMatthew G. Knepley           const PetscInt of   = 0;
61193194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
61203194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
61213194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
61223194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
61233194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
61243194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
61253194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
61263194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
61273194fc30SMatthew G. Knepley           PetscInt       o;
61283194fc30SMatthew G. Knepley 
61293194fc30SMatthew G. Knepley           /* bottom */
61303194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
61319371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
61329371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61333194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
61343194fc30SMatthew G. Knepley           /* middle */
61353194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
61363194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
61379371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
61389371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61393194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
61403194fc30SMatthew G. Knepley           }
61413194fc30SMatthew G. Knepley           /* top */
61423194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
61439371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
61449371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61453194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
61463194fc30SMatthew G. Knepley           foffset = offset;
6147e327e467SRezgar Shakeri         } else {
61485f82726aSMatthew G. Knepley           PetscInt dof;
61495f82726aSMatthew G. Knepley 
61505f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
61515f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
61525f82726aSMatthew G. Knepley           foffset = offset;
61533194fc30SMatthew G. Knepley         }
615489eabcffSMatthew G. Knepley         break;
615589eabcffSMatthew G. Knepley       case 3:
615689eabcffSMatthew G. Knepley         /* The original hex closure is
615789eabcffSMatthew G. Knepley 
615889eabcffSMatthew G. Knepley          {c,
615989eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
616089eabcffSMatthew 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,
616189eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
616289eabcffSMatthew G. Knepley          */
61635f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
61645f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
616589eabcffSMatthew G. Knepley         /* The SEM order is
616689eabcffSMatthew G. Knepley          Bottom Slice
616789eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
616889eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
616989eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
617089eabcffSMatthew G. Knepley 
617189eabcffSMatthew G. Knepley          Middle Slice (j)
617289eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
617389eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
617489eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
617589eabcffSMatthew G. Knepley 
617689eabcffSMatthew G. Knepley          Top Slice
617789eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
617889eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
617989eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
618089eabcffSMatthew G. Knepley          */
6181e327e467SRezgar Shakeri         if (continuous) {
618289eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
618389eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
618489eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
618589eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
618689eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
618789eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
618889eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
618989eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
619089eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
619189eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
619289eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
619389eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
619489eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
619589eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
619689eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
619789eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
619889eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
619989eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
620089eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
620189eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
620289eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
620389eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
620489eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
620589eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
620689eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
620789eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
620889eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
620989eabcffSMatthew G. Knepley           PetscInt       o, n;
621089eabcffSMatthew G. Knepley 
621189eabcffSMatthew G. Knepley           /* Bottom Slice */
621289eabcffSMatthew G. Knepley           /*   bottom */
621389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
62149371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
62159371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
621689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
621789eabcffSMatthew G. Knepley           /*   middle */
621889eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
621989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
62209371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
62219371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
62229371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
62239371c9d4SSatish Balay             }
622489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
62253194fc30SMatthew G. Knepley           }
622689eabcffSMatthew G. Knepley           /*   top */
622789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
62289371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
62299371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
623089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
623189eabcffSMatthew G. Knepley 
623289eabcffSMatthew G. Knepley           /* Middle Slice */
623389eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
623489eabcffSMatthew G. Knepley             /*   bottom */
623589eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
62369371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
62379371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
623889eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
623989eabcffSMatthew G. Knepley             /*   middle */
624089eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
624189eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
62429371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
62439371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
624489eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
624589eabcffSMatthew G. Knepley             }
624689eabcffSMatthew G. Knepley             /*   top */
624789eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
62489371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
62499371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
625089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
625189eabcffSMatthew G. Knepley           }
625289eabcffSMatthew G. Knepley 
625389eabcffSMatthew G. Knepley           /* Top Slice */
625489eabcffSMatthew G. Knepley           /*   bottom */
625589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
62569371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
62579371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
625889eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
625989eabcffSMatthew G. Knepley           /*   middle */
626089eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
626189eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
62629371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
62639371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
626489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
626589eabcffSMatthew G. Knepley           }
626689eabcffSMatthew G. Knepley           /*   top */
626789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
62689371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
62699371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
627089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
627189eabcffSMatthew G. Knepley 
627289eabcffSMatthew G. Knepley           foffset = offset;
6273e327e467SRezgar Shakeri         } else {
62745f82726aSMatthew G. Knepley           PetscInt dof;
62755f82726aSMatthew G. Knepley 
62765f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
62775f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
62785f82726aSMatthew G. Knepley           foffset = offset;
627989eabcffSMatthew G. Knepley         }
628089eabcffSMatthew G. Knepley         break;
6281d71ae5a4SJacob Faibussowitsch       default:
6282d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
628389eabcffSMatthew G. Knepley       }
628489eabcffSMatthew G. Knepley     }
628563a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
62863194fc30SMatthew G. Knepley     /* Check permutation */
62873194fc30SMatthew G. Knepley     {
62883194fc30SMatthew G. Knepley       PetscInt *check;
62893194fc30SMatthew G. Knepley 
62909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
62911dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
62921dca8a05SBarry Smith         check[i] = -1;
62931dca8a05SBarry 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]);
62941dca8a05SBarry Smith       }
62953194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
62961dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
62979566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
62983194fc30SMatthew G. Knepley     }
62999566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6300a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6301a05c9aa3SJed Brown       PetscInt *loc_perm;
63029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6303a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
6304a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
6305a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
6306a05c9aa3SJed Brown       }
63079566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6308a05c9aa3SJed Brown     }
6309bb197d40SJed Brown   }
63103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63113194fc30SMatthew G. Knepley }
63123194fc30SMatthew G. Knepley 
6313d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6314d71ae5a4SJacob Faibussowitsch {
6315e071409bSToby Isaac   PetscDS  prob;
6316e071409bSToby Isaac   PetscInt depth, Nf, h;
6317e071409bSToby Isaac   DMLabel  label;
6318e071409bSToby Isaac 
6319e071409bSToby Isaac   PetscFunctionBeginHot;
63209566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
6321e071409bSToby Isaac   Nf      = prob->Nf;
6322e071409bSToby Isaac   label   = dm->depthLabel;
6323e071409bSToby Isaac   *dspace = NULL;
6324e071409bSToby Isaac   if (field < Nf) {
6325e071409bSToby Isaac     PetscObject disc = prob->disc[field];
6326e071409bSToby Isaac 
6327e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
6328e071409bSToby Isaac       PetscDualSpace dsp;
6329e071409bSToby Isaac 
63309566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
63319566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
63329566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
6333e071409bSToby Isaac       h = depth - 1 - h;
6334e071409bSToby Isaac       if (h) {
63359566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6336e071409bSToby Isaac       } else {
6337e071409bSToby Isaac         *dspace = dsp;
6338e071409bSToby Isaac       }
6339e071409bSToby Isaac     }
6340e071409bSToby Isaac   }
63413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6342e071409bSToby Isaac }
6343e071409bSToby Isaac 
6344d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6345d71ae5a4SJacob Faibussowitsch {
634628351e22SJed Brown   PetscScalar       *array;
634728351e22SJed Brown   const PetscScalar *vArray;
6348d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
63491a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
6350552f7358SJed Brown 
63511b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
63529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
63539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
63549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
63559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
63563f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
63579df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
63589df71ca4SMatthew G. Knepley       PetscInt dof;
6359d9917b9dSMatthew G. Knepley 
63609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
63619df71ca4SMatthew G. Knepley       size += dof;
63629df71ca4SMatthew G. Knepley     }
63639df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
63649df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
63652a3aaacfSMatthew G. Knepley       PetscInt       dof;
63665a1bb5cfSMatthew G. Knepley 
63675a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
63689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
63695a1bb5cfSMatthew G. Knepley       size += dof;
63705a1bb5cfSMatthew G. Knepley     }
63713f7cbbe7SMatthew G. Knepley     if (!values) {
63723f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
63733ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
63743f7cbbe7SMatthew G. Knepley     }
63759566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6376982e9ed1SMatthew G. Knepley   } else {
6377982e9ed1SMatthew G. Knepley     array = *values;
6378982e9ed1SMatthew G. Knepley   }
63799df71ca4SMatthew G. Knepley   size = 0;
638028351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
63819df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
63829df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
638328351e22SJed Brown     const PetscScalar *varr;
6384d9917b9dSMatthew G. Knepley 
63859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
63869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
63878e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
6388ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
63899df71ca4SMatthew G. Knepley     size += dof;
63909df71ca4SMatthew G. Knepley   }
63919df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
63929df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
63939df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
63945a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
639528351e22SJed Brown     const PetscScalar *varr;
63965a1bb5cfSMatthew G. Knepley 
639752ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
63989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
63999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
64008e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
64015a1bb5cfSMatthew G. Knepley     if (o >= 0) {
6402ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
64035a1bb5cfSMatthew G. Knepley     } else {
6404ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
64055a1bb5cfSMatthew G. Knepley     }
64069df71ca4SMatthew G. Knepley     size += dof;
64075a1bb5cfSMatthew G. Knepley   }
640828351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
64099df71ca4SMatthew G. Knepley   if (!*values) {
64105a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
64115a1bb5cfSMatthew G. Knepley     *values = array;
64129df71ca4SMatthew G. Knepley   } else {
641363a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
64148c312ff3SMatthew G. Knepley     *csize = size;
64159df71ca4SMatthew G. Knepley   }
64163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64175a1bb5cfSMatthew G. Knepley }
6418d9917b9dSMatthew G. Knepley 
641927f02ce8SMatthew G. Knepley /* Compress out points not in the section */
6420d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6421d71ae5a4SJacob Faibussowitsch {
642227f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
642327f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
642427f02ce8SMatthew G. Knepley 
64259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
642627f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
642727f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
642827f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
642927f02ce8SMatthew G. Knepley       points[q * 2]     = r;
643027f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
643127f02ce8SMatthew G. Knepley       ++q;
643227f02ce8SMatthew G. Knepley     }
643327f02ce8SMatthew G. Knepley   }
643427f02ce8SMatthew G. Knepley   *numPoints = q;
64353ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
643627f02ce8SMatthew G. Knepley }
643727f02ce8SMatthew G. Knepley 
643897529cf3SJed Brown /* Compressed closure does not apply closure permutation */
643907218a29SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6440d71ae5a4SJacob Faibussowitsch {
644127f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
6442923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
6443923c78e0SToby Isaac 
6444923c78e0SToby Isaac   PetscFunctionBeginHot;
64459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
644607218a29SMatthew G. Knepley   if (!ornt && *clPoints) {
6447923c78e0SToby Isaac     PetscInt dof, off;
6448923c78e0SToby Isaac 
64499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
64509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
64519566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
6452923c78e0SToby Isaac     np  = dof / 2;
64538e3a54c0SPierre Jolivet     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
645427f02ce8SMatthew G. Knepley   } else {
645507218a29SMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
64569566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
6457923c78e0SToby Isaac   }
6458923c78e0SToby Isaac   *numPoints = np;
6459923c78e0SToby Isaac   *points    = pts;
6460923c78e0SToby Isaac   *clp       = cla;
64613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6462923c78e0SToby Isaac }
6463923c78e0SToby Isaac 
6464d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6465d71ae5a4SJacob Faibussowitsch {
6466923c78e0SToby Isaac   PetscFunctionBeginHot;
6467923c78e0SToby Isaac   if (!*clPoints) {
64689566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6469923c78e0SToby Isaac   } else {
64709566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
6471923c78e0SToby Isaac   }
6472923c78e0SToby Isaac   *numPoints = 0;
6473923c78e0SToby Isaac   *points    = NULL;
6474923c78e0SToby Isaac   *clSec     = NULL;
6475923c78e0SToby Isaac   *clPoints  = NULL;
6476923c78e0SToby Isaac   *clp       = NULL;
64773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6478923c78e0SToby Isaac }
6479923c78e0SToby Isaac 
6480d71ae5a4SJacob 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[])
6481d71ae5a4SJacob Faibussowitsch {
64821a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
648397e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
648497e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
64851a271a75SMatthew G. Knepley 
64861a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6487fe02ba77SJed Brown   *size = 0;
64889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
648997e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
649097e99dd9SToby Isaac     const PetscInt     point = points[2 * p];
649197e99dd9SToby Isaac     const PetscInt    *perm  = perms ? perms[p] : NULL;
649297e99dd9SToby Isaac     const PetscScalar *flip  = flips ? flips[p] : NULL;
64931a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
64941a271a75SMatthew G. Knepley     const PetscScalar *varr;
64951a271a75SMatthew G. Knepley 
64969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
64979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
64988e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
649997e99dd9SToby Isaac     if (clperm) {
650097e99dd9SToby Isaac       if (perm) {
650197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
65021a271a75SMatthew G. Knepley       } else {
650397e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
650497e99dd9SToby Isaac       }
650597e99dd9SToby Isaac       if (flip) {
650697e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
650797e99dd9SToby Isaac       }
650897e99dd9SToby Isaac     } else {
650997e99dd9SToby Isaac       if (perm) {
651097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
651197e99dd9SToby Isaac       } else {
651297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
651397e99dd9SToby Isaac       }
651497e99dd9SToby Isaac       if (flip) {
651597e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
65161a271a75SMatthew G. Knepley       }
65171a271a75SMatthew G. Knepley     }
651897e99dd9SToby Isaac     offset += dof;
651997e99dd9SToby Isaac   }
65209566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
65211a271a75SMatthew G. Knepley   *size = offset;
65223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
65231a271a75SMatthew G. Knepley }
65241a271a75SMatthew G. Knepley 
6525d71ae5a4SJacob 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[])
6526d71ae5a4SJacob Faibussowitsch {
65271a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
65281a271a75SMatthew G. Knepley 
65291a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6530fe02ba77SJed Brown   *size = 0;
65311a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
653297e99dd9SToby Isaac     PetscInt            p;
653397e99dd9SToby Isaac     const PetscInt    **perms = NULL;
653497e99dd9SToby Isaac     const PetscScalar **flips = NULL;
65351a271a75SMatthew G. Knepley 
65369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
653797e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
653897e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
653997e99dd9SToby Isaac       PetscInt           fdof, foff, b;
65401a271a75SMatthew G. Knepley       const PetscScalar *varr;
654197e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
654297e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
65431a271a75SMatthew G. Knepley 
65449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
65459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
65461a271a75SMatthew G. Knepley       varr = &vArray[foff];
654797e99dd9SToby Isaac       if (clperm) {
65489371c9d4SSatish Balay         if (perm) {
6549ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
65501a271a75SMatthew G. Knepley         } else {
6551ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
65529371c9d4SSatish Balay         }
65539371c9d4SSatish Balay         if (flip) {
6554ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
65559371c9d4SSatish Balay         }
65569371c9d4SSatish Balay       } else {
65579371c9d4SSatish Balay         if (perm) {
6558ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
65599371c9d4SSatish Balay         } else {
6560ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
65619371c9d4SSatish Balay         }
65629371c9d4SSatish Balay         if (flip) {
6563ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
65649371c9d4SSatish Balay         }
65651a271a75SMatthew G. Knepley       }
656697e99dd9SToby Isaac       offset += fdof;
65671a271a75SMatthew G. Knepley     }
65689566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
65691a271a75SMatthew G. Knepley   }
65701a271a75SMatthew G. Knepley   *size = offset;
65713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
65721a271a75SMatthew G. Knepley }
65731a271a75SMatthew G. Knepley 
657448162695SZach Atkins /*@C
657548162695SZach Atkins   DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation.
657648162695SZach Atkins 
657748162695SZach Atkins   Not collective
657848162695SZach Atkins 
657948162695SZach Atkins   Input Parameters:
658048162695SZach Atkins + dm        - The `DM`
658148162695SZach Atkins . section   - The section describing the layout in `v`, or `NULL` to use the default section
658248162695SZach Atkins . useClPerm - Flag for whether the provided closure permutation should be applied to the values
658348162695SZach Atkins . v         - The local vector
658448162695SZach Atkins . point     - The point in the `DM`
658548162695SZach Atkins - ornt      - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0.
658648162695SZach Atkins 
658748162695SZach Atkins   Input/Output Parameters:
658848162695SZach Atkins + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
658948162695SZach Atkins - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
659048162695SZach Atkins            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
659148162695SZach Atkins 
659248162695SZach Atkins   Level: advanced
659348162695SZach Atkins 
659448162695SZach Atkins   Notes:
659548162695SZach Atkins   `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
659648162695SZach Atkins   calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat`
659748162695SZach Atkins   assembly function, and a user may already have allocated storage for this operation.
659848162695SZach Atkins 
659948162695SZach Atkins   Fortran Notes:
660048162695SZach 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.
660148162695SZach Atkins   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
660248162695SZach Atkins 
660348162695SZach Atkins   `values` must be declared with
660448162695SZach Atkins .vb
660548162695SZach Atkins   PetscScalar,dimension(:),pointer   :: values
660648162695SZach Atkins .ve
660748162695SZach Atkins   and it will be allocated internally by PETSc to hold the values returned
660848162695SZach Atkins 
660948162695SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`
661048162695SZach Atkins @*/
661148162695SZach Atkins PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
661207218a29SMatthew G. Knepley {
661307218a29SMatthew G. Knepley   PetscSection    clSection;
661407218a29SMatthew G. Knepley   IS              clPoints;
661507218a29SMatthew G. Knepley   PetscInt       *points = NULL;
6616e8e188d2SZach Atkins   const PetscInt *clp, *perm = NULL;
661707218a29SMatthew G. Knepley   PetscInt        depth, numFields, numPoints, asize;
661807218a29SMatthew G. Knepley 
661907218a29SMatthew G. Knepley   PetscFunctionBeginHot;
662007218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
662107218a29SMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
662207218a29SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6623e8e188d2SZach Atkins   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
662407218a29SMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
662507218a29SMatthew G. Knepley   PetscCall(PetscSectionGetNumFields(section, &numFields));
662607218a29SMatthew G. Knepley   if (depth == 1 && numFields < 2) {
662707218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
662807218a29SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
662907218a29SMatthew G. Knepley   }
663007218a29SMatthew G. Knepley   /* Get points */
663107218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
663207218a29SMatthew G. Knepley   /* Get sizes */
663307218a29SMatthew G. Knepley   asize = 0;
663407218a29SMatthew G. Knepley   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
663507218a29SMatthew G. Knepley     PetscInt dof;
663607218a29SMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, points[p], &dof));
663707218a29SMatthew G. Knepley     asize += dof;
663807218a29SMatthew G. Knepley   }
663907218a29SMatthew G. Knepley   if (values) {
664007218a29SMatthew G. Knepley     const PetscScalar *vArray;
664107218a29SMatthew G. Knepley     PetscInt           size;
664207218a29SMatthew G. Knepley 
664307218a29SMatthew G. Knepley     if (*values) {
664407218a29SMatthew 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);
664507218a29SMatthew G. Knepley     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6646e8e188d2SZach Atkins     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
664707218a29SMatthew G. Knepley     PetscCall(VecGetArrayRead(v, &vArray));
664807218a29SMatthew G. Knepley     /* Get values */
664907218a29SMatthew G. Knepley     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
665007218a29SMatthew G. Knepley     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
665107218a29SMatthew 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);
665207218a29SMatthew G. Knepley     /* Cleanup array */
665307218a29SMatthew G. Knepley     PetscCall(VecRestoreArrayRead(v, &vArray));
665407218a29SMatthew G. Knepley   }
665507218a29SMatthew G. Knepley   if (csize) *csize = asize;
665607218a29SMatthew G. Knepley   /* Cleanup points */
665707218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
665807218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
665907218a29SMatthew G. Knepley }
666007218a29SMatthew G. Knepley 
6661552f7358SJed Brown /*@C
6662552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6663552f7358SJed Brown 
6664552f7358SJed Brown   Not collective
6665552f7358SJed Brown 
6666552f7358SJed Brown   Input Parameters:
6667a1cb98faSBarry Smith + dm      - The `DM`
666820f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6669552f7358SJed Brown . v       - The local vector
6670a1cb98faSBarry Smith - point   - The point in the `DM`
6671552f7358SJed Brown 
66726b867d5aSJose E. Roman   Input/Output Parameters:
667320f4b53cSBarry Smith + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
66742c9a7b26SBarry Smith - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
66752c9a7b26SBarry Smith            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
667622c1ee49SMatthew G. Knepley 
6677552f7358SJed Brown   Level: intermediate
6678552f7358SJed Brown 
6679a1cb98faSBarry Smith   Notes:
668044a422c4SJames Wright   This is used for getting the all values in a `Vec` in the closure of a mesh point.
668144a422c4SJames Wright   To get only the values in the closure of a mesh point at a specific depth (for example, at mesh vertices), use `DMPlexVecGetClosureAtDepth()`.
668244a422c4SJames Wright 
668320f4b53cSBarry Smith   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6684a1cb98faSBarry Smith   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6685a1cb98faSBarry Smith   assembly function, and a user may already have allocated storage for this operation.
6686a1cb98faSBarry Smith 
6687a1cb98faSBarry Smith   A typical use could be
6688a1cb98faSBarry Smith .vb
6689a1cb98faSBarry Smith    values = NULL;
6690a1cb98faSBarry Smith    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6691a1cb98faSBarry Smith    for (cl = 0; cl < clSize; ++cl) {
6692a1cb98faSBarry Smith      <Compute on closure>
6693a1cb98faSBarry Smith    }
6694a1cb98faSBarry Smith    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6695a1cb98faSBarry Smith .ve
6696a1cb98faSBarry Smith   or
6697a1cb98faSBarry Smith .vb
6698a1cb98faSBarry Smith    PetscMalloc1(clMaxSize, &values);
6699a1cb98faSBarry Smith    for (p = pStart; p < pEnd; ++p) {
6700a1cb98faSBarry Smith      clSize = clMaxSize;
6701a1cb98faSBarry Smith      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6702a1cb98faSBarry Smith      for (cl = 0; cl < clSize; ++cl) {
6703a1cb98faSBarry Smith        <Compute on closure>
6704a1cb98faSBarry Smith      }
6705a1cb98faSBarry Smith    }
6706a1cb98faSBarry Smith    PetscFree(values);
6707a1cb98faSBarry Smith .ve
6708a1cb98faSBarry Smith 
670960225df5SJacob Faibussowitsch   Fortran Notes:
6710ce78bad3SBarry 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.
6711ce78bad3SBarry Smith   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6712a1cb98faSBarry Smith 
6713f13dfd9eSBarry Smith   `values` must be declared with
6714f13dfd9eSBarry Smith .vb
6715f13dfd9eSBarry Smith   PetscScalar,dimension(:),pointer   :: values
6716f13dfd9eSBarry Smith .ve
6717f13dfd9eSBarry Smith   and it will be allocated internally by PETSc to hold the values returned
6718f13dfd9eSBarry Smith 
671944a422c4SJames Wright .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosureAtDepth()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6720552f7358SJed Brown @*/
6721d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6722d71ae5a4SJacob Faibussowitsch {
6723d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
672448162695SZach Atkins   PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values));
67253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6726552f7358SJed Brown }
6727552f7358SJed Brown 
672844a422c4SJames Wright /*@C
672944a422c4SJames Wright   DMPlexVecGetClosureAtDepth - Get an array of the values on the closure of 'point' that are at a specific depth
673044a422c4SJames Wright 
673144a422c4SJames Wright   Not collective
673244a422c4SJames Wright 
673344a422c4SJames Wright   Input Parameters:
673444a422c4SJames Wright + dm      - The `DM`
673544a422c4SJames Wright . section - The section describing the layout in `v`, or `NULL` to use the default section
673644a422c4SJames Wright . v       - The local vector
673744a422c4SJames Wright . depth   - The depth of mesh points that should be returned
673844a422c4SJames Wright - point   - The point in the `DM`
673944a422c4SJames Wright 
674044a422c4SJames Wright   Input/Output Parameters:
674144a422c4SJames Wright + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
674244a422c4SJames Wright - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
674344a422c4SJames Wright            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
674444a422c4SJames Wright 
674544a422c4SJames Wright   Level: intermediate
674644a422c4SJames Wright 
674744a422c4SJames Wright   Notes:
674844a422c4SJames Wright   This is used for getting the values in a `Vec` associated with specific mesh points.
674944a422c4SJames 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()`.
675044a422c4SJames Wright 
675144a422c4SJames Wright   `DMPlexVecGetClosureAtDepth()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
675244a422c4SJames Wright   calling function. This is because `DMPlexVecGetClosureAtDepth()` is typically called in the inner loop of a `Vec` or `Mat`
675344a422c4SJames Wright   assembly function, and a user may already have allocated storage for this operation.
675444a422c4SJames Wright 
675544a422c4SJames Wright   A typical use could be
675644a422c4SJames Wright .vb
675744a422c4SJames Wright    values = NULL;
675844a422c4SJames Wright    PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values));
675944a422c4SJames Wright    for (cl = 0; cl < clSize; ++cl) {
676044a422c4SJames Wright      <Compute on closure>
676144a422c4SJames Wright    }
676244a422c4SJames Wright    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
676344a422c4SJames Wright .ve
676444a422c4SJames Wright   or
676544a422c4SJames Wright .vb
676644a422c4SJames Wright    PetscMalloc1(clMaxSize, &values);
676744a422c4SJames Wright    for (p = pStart; p < pEnd; ++p) {
676844a422c4SJames Wright      clSize = clMaxSize;
676944a422c4SJames Wright      PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values));
677044a422c4SJames Wright      for (cl = 0; cl < clSize; ++cl) {
677144a422c4SJames Wright        <Compute on closure>
677244a422c4SJames Wright      }
677344a422c4SJames Wright    }
677444a422c4SJames Wright    PetscFree(values);
677544a422c4SJames Wright .ve
677644a422c4SJames Wright 
677744a422c4SJames Wright   Fortran Notes:
677844a422c4SJames 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.
677944a422c4SJames Wright   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
678044a422c4SJames Wright 
678144a422c4SJames Wright   `values` must be declared with
678244a422c4SJames Wright .vb
678344a422c4SJames Wright   PetscScalar,dimension(:),pointer   :: values
678444a422c4SJames Wright .ve
678544a422c4SJames Wright   and it will be allocated internally by PETSc to hold the values returned
678644a422c4SJames Wright 
678744a422c4SJames Wright .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
678844a422c4SJames Wright @*/
678944a422c4SJames Wright PetscErrorCode DMPlexVecGetClosureAtDepth(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6790d71ae5a4SJacob Faibussowitsch {
6791e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6792e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6793e5c487bfSMatthew G. Knepley   IS                 clPoints;
6794e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6795e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6796e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6797c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6798c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6799e5c487bfSMatthew G. Knepley 
6800e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6801e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
68029566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6803e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6804e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
68059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
68069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
68079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6808e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
68099566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
68103ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6811e5c487bfSMatthew G. Knepley   }
6812e5c487bfSMatthew G. Knepley   /* Get points */
681307218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6814c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6815c459fbc1SJed Brown     PetscInt dof;
68169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6817c459fbc1SJed Brown     clsize += dof;
6818c459fbc1SJed Brown   }
68199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6820e5c487bfSMatthew G. Knepley   /* Filter points */
6821e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6822e5c487bfSMatthew G. Knepley     PetscInt dep;
6823e5c487bfSMatthew G. Knepley 
68249566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6825e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6826e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6827e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6828e5c487bfSMatthew G. Knepley     ++Np;
6829e5c487bfSMatthew G. Knepley   }
6830e5c487bfSMatthew G. Knepley   /* Get array */
6831e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6832e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6833e5c487bfSMatthew G. Knepley 
6834e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
68359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6836e5c487bfSMatthew G. Knepley       asize += dof;
6837e5c487bfSMatthew G. Knepley     }
6838e5c487bfSMatthew G. Knepley     if (!values) {
68399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6840e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
68413ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
6842e5c487bfSMatthew G. Knepley     }
68439566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6844e5c487bfSMatthew G. Knepley   } else {
6845e5c487bfSMatthew G. Knepley     array = *values;
6846e5c487bfSMatthew G. Knepley   }
68479566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6848e5c487bfSMatthew G. Knepley   /* Get values */
68499566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
68509566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6851e5c487bfSMatthew G. Knepley   /* Cleanup points */
68529566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6853e5c487bfSMatthew G. Knepley   /* Cleanup array */
68549566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6855e5c487bfSMatthew G. Knepley   if (!*values) {
6856e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6857e5c487bfSMatthew G. Knepley     *values = array;
6858e5c487bfSMatthew G. Knepley   } else {
685963a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6860e5c487bfSMatthew G. Knepley     *csize = size;
6861e5c487bfSMatthew G. Knepley   }
68623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6863e5c487bfSMatthew G. Knepley }
6864e5c487bfSMatthew G. Knepley 
6865552f7358SJed Brown /*@C
6866f13dfd9eSBarry Smith   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()`
6867552f7358SJed Brown 
6868552f7358SJed Brown   Not collective
6869552f7358SJed Brown 
6870552f7358SJed Brown   Input Parameters:
6871a1cb98faSBarry Smith + dm      - The `DM`
687220f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6873552f7358SJed Brown . v       - The local vector
6874a1cb98faSBarry Smith . point   - The point in the `DM`
687520f4b53cSBarry Smith . csize   - The number of values in the closure, or `NULL`
6876f13dfd9eSBarry Smith - values  - The array of values
6877552f7358SJed Brown 
6878552f7358SJed Brown   Level: intermediate
6879552f7358SJed Brown 
6880a1cb98faSBarry Smith   Note:
688120f4b53cSBarry Smith   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6882a1cb98faSBarry Smith 
6883f13dfd9eSBarry Smith   Fortran Note:
6884ce78bad3SBarry 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.
6885ce78bad3SBarry Smith   In that case one may pass `PETSC_NULL_INTEGER` for `csize`.
6886a1cb98faSBarry Smith 
68871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6888552f7358SJed Brown @*/
6889d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6890d71ae5a4SJacob Faibussowitsch {
6891552f7358SJed Brown   PetscInt size = 0;
6892552f7358SJed Brown 
6893552f7358SJed Brown   PetscFunctionBegin;
6894552f7358SJed Brown   /* Should work without recalculating size */
68959566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6896c9fdaa05SMatthew G. Knepley   *values = NULL;
68973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6898552f7358SJed Brown }
6899552f7358SJed Brown 
6900d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6901d71ae5a4SJacob Faibussowitsch {
69029371c9d4SSatish Balay   *x += y;
69039371c9d4SSatish Balay }
6904d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6905d71ae5a4SJacob Faibussowitsch {
69069371c9d4SSatish Balay   *x = y;
69079371c9d4SSatish Balay }
6908552f7358SJed Brown 
6909d71ae5a4SJacob 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[])
6910d71ae5a4SJacob Faibussowitsch {
6911552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6912552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6913552f7358SJed Brown   PetscScalar    *a;
6914552f7358SJed Brown   PetscInt        off, cind = 0, k;
6915552f7358SJed Brown 
6916552f7358SJed Brown   PetscFunctionBegin;
69179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
69189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6919552f7358SJed Brown   a = &array[off];
6920552f7358SJed Brown   if (!cdof || setBC) {
692197e99dd9SToby Isaac     if (clperm) {
69229371c9d4SSatish Balay       if (perm) {
6923ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6924552f7358SJed Brown       } else {
6925ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
69269371c9d4SSatish Balay       }
69279371c9d4SSatish Balay     } else {
69289371c9d4SSatish Balay       if (perm) {
6929ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
69309371c9d4SSatish Balay       } else {
6931ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
69329371c9d4SSatish Balay       }
6933552f7358SJed Brown     }
6934552f7358SJed Brown   } else {
69359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
693697e99dd9SToby Isaac     if (clperm) {
69379371c9d4SSatish Balay       if (perm) {
69389371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
69399371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69409371c9d4SSatish Balay             ++cind;
69419371c9d4SSatish Balay             continue;
69429371c9d4SSatish Balay           }
694397e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6944552f7358SJed Brown         }
6945552f7358SJed Brown       } else {
6946552f7358SJed Brown         for (k = 0; k < dof; ++k) {
69479371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69489371c9d4SSatish Balay             ++cind;
69499371c9d4SSatish Balay             continue;
69509371c9d4SSatish Balay           }
695197e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
695297e99dd9SToby Isaac         }
695397e99dd9SToby Isaac       }
695497e99dd9SToby Isaac     } else {
695597e99dd9SToby Isaac       if (perm) {
695697e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
69579371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69589371c9d4SSatish Balay             ++cind;
69599371c9d4SSatish Balay             continue;
69609371c9d4SSatish Balay           }
696197e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
696297e99dd9SToby Isaac         }
696397e99dd9SToby Isaac       } else {
696497e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
69659371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
69669371c9d4SSatish Balay             ++cind;
69679371c9d4SSatish Balay             continue;
69689371c9d4SSatish Balay           }
696997e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
697097e99dd9SToby Isaac         }
6971552f7358SJed Brown       }
6972552f7358SJed Brown     }
6973552f7358SJed Brown   }
69743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6975552f7358SJed Brown }
6976552f7358SJed Brown 
6977d71ae5a4SJacob 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[])
6978d71ae5a4SJacob Faibussowitsch {
6979a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6980a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6981a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6982a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6983a5e93ea8SMatthew G. Knepley 
6984a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
69859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
69869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6987a5e93ea8SMatthew G. Knepley   a = &array[off];
6988a5e93ea8SMatthew G. Knepley   if (cdof) {
69899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
699097e99dd9SToby Isaac     if (clperm) {
699197e99dd9SToby Isaac       if (perm) {
6992a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6993a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
699497e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
699597e99dd9SToby Isaac             cind++;
6996a5e93ea8SMatthew G. Knepley           }
6997a5e93ea8SMatthew G. Knepley         }
6998a5e93ea8SMatthew G. Knepley       } else {
6999a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
7000a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
700197e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
700297e99dd9SToby Isaac             cind++;
700397e99dd9SToby Isaac           }
700497e99dd9SToby Isaac         }
700597e99dd9SToby Isaac       }
700697e99dd9SToby Isaac     } else {
700797e99dd9SToby Isaac       if (perm) {
700897e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
700997e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
701097e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
701197e99dd9SToby Isaac             cind++;
701297e99dd9SToby Isaac           }
701397e99dd9SToby Isaac         }
701497e99dd9SToby Isaac       } else {
701597e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
701697e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
701797e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
701897e99dd9SToby Isaac             cind++;
701997e99dd9SToby Isaac           }
7020a5e93ea8SMatthew G. Knepley         }
7021a5e93ea8SMatthew G. Knepley       }
7022a5e93ea8SMatthew G. Knepley     }
7023a5e93ea8SMatthew G. Knepley   }
70243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7025a5e93ea8SMatthew G. Knepley }
7026a5e93ea8SMatthew G. Knepley 
7027d71ae5a4SJacob 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[])
7028d71ae5a4SJacob Faibussowitsch {
7029552f7358SJed Brown   PetscScalar    *a;
70301a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
70311a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
703297e99dd9SToby Isaac   PetscInt        cind = 0, b;
7033552f7358SJed Brown 
7034552f7358SJed Brown   PetscFunctionBegin;
70359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
70369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
70379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
70381a271a75SMatthew G. Knepley   a = &array[foff];
7039552f7358SJed Brown   if (!fcdof || setBC) {
704097e99dd9SToby Isaac     if (clperm) {
70419371c9d4SSatish Balay       if (perm) {
7042ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7043552f7358SJed Brown       } else {
7044ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
70459371c9d4SSatish Balay       }
70469371c9d4SSatish Balay     } else {
70479371c9d4SSatish Balay       if (perm) {
7048ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
70499371c9d4SSatish Balay       } else {
7050ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
70519371c9d4SSatish Balay       }
7052552f7358SJed Brown     }
7053552f7358SJed Brown   } else {
70549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
705597e99dd9SToby Isaac     if (clperm) {
705697e99dd9SToby Isaac       if (perm) {
705797e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70589371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70599371c9d4SSatish Balay             ++cind;
70609371c9d4SSatish Balay             continue;
70619371c9d4SSatish Balay           }
706297e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7063552f7358SJed Brown         }
7064552f7358SJed Brown       } else {
706597e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70669371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70679371c9d4SSatish Balay             ++cind;
70689371c9d4SSatish Balay             continue;
70699371c9d4SSatish Balay           }
707097e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
707197e99dd9SToby Isaac         }
707297e99dd9SToby Isaac       }
707397e99dd9SToby Isaac     } else {
707497e99dd9SToby Isaac       if (perm) {
707597e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70769371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70779371c9d4SSatish Balay             ++cind;
70789371c9d4SSatish Balay             continue;
70799371c9d4SSatish Balay           }
708097e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
708197e99dd9SToby Isaac         }
708297e99dd9SToby Isaac       } else {
708397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
70849371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
70859371c9d4SSatish Balay             ++cind;
70869371c9d4SSatish Balay             continue;
70879371c9d4SSatish Balay           }
708897e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7089552f7358SJed Brown         }
7090552f7358SJed Brown       }
7091552f7358SJed Brown     }
7092552f7358SJed Brown   }
70931a271a75SMatthew G. Knepley   *offset += fdof;
70943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7095552f7358SJed Brown }
7096552f7358SJed Brown 
7097d71ae5a4SJacob 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[])
7098d71ae5a4SJacob Faibussowitsch {
7099a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
71001a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
71011a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
71025da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
7103ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
7104a5e93ea8SMatthew G. Knepley 
7105a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
71069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
71079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
71089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
71099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
71101a271a75SMatthew G. Knepley   a = &array[foff];
7111a5e93ea8SMatthew G. Knepley   if (fcdof) {
7112ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
71139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
711497e99dd9SToby Isaac     if (clperm) {
711597e99dd9SToby Isaac       if (perm) {
7116ba322698SMatthew G. Knepley         if (comps) {
7117ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7118ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71199371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71209371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71219371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71229371c9d4SSatish Balay             }
71239371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71249371c9d4SSatish Balay               ++cind;
71259371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71269371c9d4SSatish Balay             }
7127ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7128ba322698SMatthew G. Knepley           }
7129ba322698SMatthew G. Knepley         } else {
713097e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
713197e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
713297e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
7133a5e93ea8SMatthew G. Knepley               ++cind;
7134a5e93ea8SMatthew G. Knepley             }
7135a5e93ea8SMatthew G. Knepley           }
7136ba322698SMatthew G. Knepley         }
7137ba322698SMatthew G. Knepley       } else {
7138ba322698SMatthew G. Knepley         if (comps) {
7139ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7140ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71419371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71429371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71439371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71449371c9d4SSatish Balay             }
71459371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71469371c9d4SSatish Balay               ++cind;
71479371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71489371c9d4SSatish Balay             }
7149ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
7150ba322698SMatthew G. Knepley           }
7151a5e93ea8SMatthew G. Knepley         } else {
715297e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
715397e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
715497e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
715597e99dd9SToby Isaac               ++cind;
715697e99dd9SToby Isaac             }
715797e99dd9SToby Isaac           }
715897e99dd9SToby Isaac         }
7159ba322698SMatthew G. Knepley       }
716097e99dd9SToby Isaac     } else {
716197e99dd9SToby Isaac       if (perm) {
7162ba322698SMatthew G. Knepley         if (comps) {
7163ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7164ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71659371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71669371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71679371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71689371c9d4SSatish Balay             }
71699371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71709371c9d4SSatish Balay               ++cind;
71719371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71729371c9d4SSatish Balay             }
7173ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
7174ba322698SMatthew G. Knepley           }
7175ba322698SMatthew G. Knepley         } else {
717697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
717797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
717897e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
717997e99dd9SToby Isaac               ++cind;
718097e99dd9SToby Isaac             }
718197e99dd9SToby Isaac           }
7182ba322698SMatthew G. Knepley         }
7183ba322698SMatthew G. Knepley       } else {
7184ba322698SMatthew G. Knepley         if (comps) {
7185ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
7186ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
71879371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
71889371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
71899371c9d4SSatish Balay               ncSet = PETSC_TRUE;
71909371c9d4SSatish Balay             }
71919371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
71929371c9d4SSatish Balay               ++cind;
71939371c9d4SSatish Balay               fcSet = PETSC_TRUE;
71949371c9d4SSatish Balay             }
7195ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7196ba322698SMatthew G. Knepley           }
719797e99dd9SToby Isaac         } else {
719897e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
719997e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
720097e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
7201a5e93ea8SMatthew G. Knepley               ++cind;
7202a5e93ea8SMatthew G. Knepley             }
7203a5e93ea8SMatthew G. Knepley           }
7204a5e93ea8SMatthew G. Knepley         }
7205a5e93ea8SMatthew G. Knepley       }
7206a5e93ea8SMatthew G. Knepley     }
7207ba322698SMatthew G. Knepley   }
72081a271a75SMatthew G. Knepley   *offset += fdof;
72093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7210a5e93ea8SMatthew G. Knepley }
7211a5e93ea8SMatthew G. Knepley 
7212d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7213d71ae5a4SJacob Faibussowitsch {
7214552f7358SJed Brown   PetscScalar    *array;
72151b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
72161b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
7217552f7358SJed Brown 
72181b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
72199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
72209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
72219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
72229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
72239566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7224b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
7225b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
7226b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
7227b6ebb6e6SMatthew G. Knepley 
72289371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
72299371c9d4SSatish Balay       dof = 0;
72309371c9d4SSatish Balay       continue;
72319371c9d4SSatish Balay     }
72329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
7233b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
7234b6ebb6e6SMatthew G. Knepley     {
7235b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7236b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
7237b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
7238b6ebb6e6SMatthew G. Knepley 
72399566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
72409566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
7241b6ebb6e6SMatthew G. Knepley       a = &array[coff];
7242b6ebb6e6SMatthew G. Knepley       if (!cdof) {
7243b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
7244ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
7245b6ebb6e6SMatthew G. Knepley         } else {
7246ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
7247b6ebb6e6SMatthew G. Knepley         }
7248b6ebb6e6SMatthew G. Knepley       } else {
72499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
7250b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
7251b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
72529371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
72539371c9d4SSatish Balay               ++cind;
72549371c9d4SSatish Balay               continue;
72559371c9d4SSatish Balay             }
7256b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
7257b6ebb6e6SMatthew G. Knepley           }
7258b6ebb6e6SMatthew G. Knepley         } else {
7259b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
72609371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
72619371c9d4SSatish Balay               ++cind;
72629371c9d4SSatish Balay               continue;
72639371c9d4SSatish Balay             }
7264b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
7265b6ebb6e6SMatthew G. Knepley           }
7266b6ebb6e6SMatthew G. Knepley         }
7267b6ebb6e6SMatthew G. Knepley       }
7268b6ebb6e6SMatthew G. Knepley     }
7269b6ebb6e6SMatthew G. Knepley   }
72709566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
72713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7272b6ebb6e6SMatthew G. Knepley }
72731b406b76SMatthew G. Knepley 
72741b406b76SMatthew G. Knepley /*@C
727520f4b53cSBarry Smith   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
72761b406b76SMatthew G. Knepley 
72771b406b76SMatthew G. Knepley   Not collective
72781b406b76SMatthew G. Knepley 
72791b406b76SMatthew G. Knepley   Input Parameters:
7280a1cb98faSBarry Smith + dm      - The `DM`
728120f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
72821b406b76SMatthew G. Knepley . v       - The local vector
728320f4b53cSBarry Smith . point   - The point in the `DM`
72841b406b76SMatthew G. Knepley . values  - The array of values
7285a1cb98faSBarry Smith - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
7286a1cb98faSBarry Smith             where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
72871b406b76SMatthew G. Knepley 
72881b406b76SMatthew G. Knepley   Level: intermediate
72891b406b76SMatthew G. Knepley 
7290f13dfd9eSBarry Smith   Note:
7291f13dfd9eSBarry Smith   Usually the input arrays were obtained with `DMPlexVecGetClosure()`
7292f13dfd9eSBarry Smith 
72931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
72941b406b76SMatthew G. Knepley @*/
7295d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7296d71ae5a4SJacob Faibussowitsch {
72971b406b76SMatthew G. Knepley   PetscSection    clSection;
72981b406b76SMatthew G. Knepley   IS              clPoints;
72991b406b76SMatthew G. Knepley   PetscScalar    *array;
73001b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
730127f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
7302c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
73031b406b76SMatthew G. Knepley 
73041a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
73051b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
73069566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
73071a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
73081a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
73099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
73109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
73111b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
73129566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
73133ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
73141b406b76SMatthew G. Knepley   }
73151a271a75SMatthew G. Knepley   /* Get points */
731607218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7317c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
7318c459fbc1SJed Brown     PetscInt dof;
73199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7320c459fbc1SJed Brown     clsize += dof;
7321c459fbc1SJed Brown   }
73229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
73231a271a75SMatthew G. Knepley   /* Get array */
73249566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
73251a271a75SMatthew G. Knepley   /* Get values */
7326ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
732797e99dd9SToby Isaac     PetscInt offset = 0, f;
7328552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
732997e99dd9SToby Isaac       const PetscInt    **perms = NULL;
733097e99dd9SToby Isaac       const PetscScalar **flips = NULL;
733197e99dd9SToby Isaac 
73329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7333552f7358SJed Brown       switch (mode) {
7334552f7358SJed Brown       case INSERT_VALUES:
733597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
733697e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
733797e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
733897e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73393ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
73409371c9d4SSatish Balay         }
73419371c9d4SSatish Balay         break;
7342552f7358SJed Brown       case INSERT_ALL_VALUES:
734397e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
734497e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
734597e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
734697e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73473ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
73489371c9d4SSatish Balay         }
73499371c9d4SSatish Balay         break;
7350a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
735197e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
735297e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
735397e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
735497e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73553ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
73569371c9d4SSatish Balay         }
73579371c9d4SSatish Balay         break;
7358552f7358SJed Brown       case ADD_VALUES:
735997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
736097e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
736197e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
736297e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73633ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
73649371c9d4SSatish Balay         }
73659371c9d4SSatish Balay         break;
7366552f7358SJed Brown       case ADD_ALL_VALUES:
736797e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
736897e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
736997e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
737097e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73713ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
73729371c9d4SSatish Balay         }
73739371c9d4SSatish Balay         break;
7374304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
737597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
737697e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
737797e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
737897e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
73793ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
73809371c9d4SSatish Balay         }
73819371c9d4SSatish Balay         break;
7382d71ae5a4SJacob Faibussowitsch       default:
7383d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7384552f7358SJed Brown       }
73859566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
73861a271a75SMatthew G. Knepley     }
7387552f7358SJed Brown   } else {
73881a271a75SMatthew G. Knepley     PetscInt            dof, off;
738997e99dd9SToby Isaac     const PetscInt    **perms = NULL;
739097e99dd9SToby Isaac     const PetscScalar **flips = NULL;
73911a271a75SMatthew G. Knepley 
73929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7393552f7358SJed Brown     switch (mode) {
7394552f7358SJed Brown     case INSERT_VALUES:
739597e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
739697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
739797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
739897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
73999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74003ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
74019371c9d4SSatish Balay       }
74029371c9d4SSatish Balay       break;
7403552f7358SJed Brown     case INSERT_ALL_VALUES:
740497e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
740597e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
740697e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
740797e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74093ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
74109371c9d4SSatish Balay       }
74119371c9d4SSatish Balay       break;
7412a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
741397e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
741497e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
741597e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
741697e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74183ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
74199371c9d4SSatish Balay       }
74209371c9d4SSatish Balay       break;
7421552f7358SJed Brown     case ADD_VALUES:
742297e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
742397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
742497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
742597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74273ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
74289371c9d4SSatish Balay       }
74299371c9d4SSatish Balay       break;
7430552f7358SJed Brown     case ADD_ALL_VALUES:
743197e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
743297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
743397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
743497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74363ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
74379371c9d4SSatish Balay       }
74389371c9d4SSatish Balay       break;
7439304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
744097e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
744197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
744297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
744397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
74449566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
74453ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
74469371c9d4SSatish Balay       }
74479371c9d4SSatish Balay       break;
7448d71ae5a4SJacob Faibussowitsch     default:
7449d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7450552f7358SJed Brown     }
74519566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7452552f7358SJed Brown   }
74531a271a75SMatthew G. Knepley   /* Cleanup points */
74549566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
74551a271a75SMatthew G. Knepley   /* Cleanup array */
74569566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
74573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7458552f7358SJed Brown }
7459552f7358SJed Brown 
74605f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
7461d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7462d71ae5a4SJacob Faibussowitsch {
74635f790a90SMatthew G. Knepley   PetscFunctionBegin;
746411cc89d2SBarry Smith   *contains = PETSC_TRUE;
74655f790a90SMatthew G. Knepley   if (label) {
7466d6177c40SToby Isaac     PetscInt fdof;
74675f790a90SMatthew G. Knepley 
746811cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
746911cc89d2SBarry Smith     if (!*contains) {
74709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
74715f790a90SMatthew G. Knepley       *offset += fdof;
74723ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
74735f790a90SMatthew G. Knepley     }
74745f790a90SMatthew G. Knepley   }
74753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
74765f790a90SMatthew G. Knepley }
74775f790a90SMatthew G. Knepley 
747897529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7479d71ae5a4SJacob 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)
7480d71ae5a4SJacob Faibussowitsch {
7481e07394fbSMatthew G. Knepley   PetscSection    clSection;
7482e07394fbSMatthew G. Knepley   IS              clPoints;
7483e07394fbSMatthew G. Knepley   PetscScalar    *array;
7484e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
748597529cf3SJed Brown   const PetscInt *clp;
7486e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
748797e99dd9SToby Isaac   PetscInt        offset = 0, f;
7488e07394fbSMatthew G. Knepley 
7489e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
7490e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
74919566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7492e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7493e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
74949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7495e07394fbSMatthew G. Knepley   /* Get points */
749607218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7497e07394fbSMatthew G. Knepley   /* Get array */
74989566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7499e07394fbSMatthew G. Knepley   /* Get values */
7500e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
750197e99dd9SToby Isaac     const PetscInt    **perms = NULL;
750297e99dd9SToby Isaac     const PetscScalar **flips = NULL;
750311cc89d2SBarry Smith     PetscBool           contains;
750497e99dd9SToby Isaac 
7505e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
7506e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
7507e07394fbSMatthew G. Knepley         PetscInt fdof;
75089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7509e07394fbSMatthew G. Knepley         offset += fdof;
7510e07394fbSMatthew G. Knepley       }
7511e07394fbSMatthew G. Knepley       continue;
7512e07394fbSMatthew G. Knepley     }
75139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7514e07394fbSMatthew G. Knepley     switch (mode) {
7515e07394fbSMatthew G. Knepley     case INSERT_VALUES:
751697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
751797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
751897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
751997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
752011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
752111cc89d2SBarry Smith         if (!contains) continue;
75229566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
75239371c9d4SSatish Balay       }
75249371c9d4SSatish Balay       break;
7525e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
752697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
752797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
752897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
752997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
753011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
753111cc89d2SBarry Smith         if (!contains) continue;
75329566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
75339371c9d4SSatish Balay       }
75349371c9d4SSatish Balay       break;
7535e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
753697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
753797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
753897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
753997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
754011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
754111cc89d2SBarry Smith         if (!contains) continue;
75429566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
75439371c9d4SSatish Balay       }
75449371c9d4SSatish Balay       break;
7545e07394fbSMatthew G. Knepley     case ADD_VALUES:
754697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
754797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
754897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
754997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
755011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
755111cc89d2SBarry Smith         if (!contains) continue;
75529566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
75539371c9d4SSatish Balay       }
75549371c9d4SSatish Balay       break;
7555e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
755697e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
755797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
755897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
755997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
756011cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
756111cc89d2SBarry Smith         if (!contains) continue;
75629566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
75639371c9d4SSatish Balay       }
75649371c9d4SSatish Balay       break;
7565d71ae5a4SJacob Faibussowitsch     default:
7566d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7567e07394fbSMatthew G. Knepley     }
75689566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7569e07394fbSMatthew G. Knepley   }
7570e07394fbSMatthew G. Knepley   /* Cleanup points */
75719566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7572e07394fbSMatthew G. Knepley   /* Cleanup array */
75739566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
75743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7575e07394fbSMatthew G. Knepley }
7576e07394fbSMatthew G. Knepley 
7577d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7578d71ae5a4SJacob Faibussowitsch {
7579552f7358SJed Brown   PetscMPIInt rank;
7580552f7358SJed Brown   PetscInt    i, j;
7581552f7358SJed Brown 
7582552f7358SJed Brown   PetscFunctionBegin;
75839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
758463a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
758563a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
758663a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7587b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
75883ba16761SJacob Faibussowitsch   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7589b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
75909566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7591b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
7592519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
75939566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7594552f7358SJed Brown #else
75959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7596552f7358SJed Brown #endif
7597552f7358SJed Brown     }
75989566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7599552f7358SJed Brown   }
76003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7601552f7358SJed Brown }
7602552f7358SJed Brown 
760305586334SMatthew G. Knepley /*
760405586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
760505586334SMatthew G. Knepley 
760605586334SMatthew G. Knepley   Input Parameters:
760705586334SMatthew G. Knepley + section - The section for this data layout
760836fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
760905586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
761005586334SMatthew G. Knepley . off     - The global offset of this point
761105586334SMatthew G. Knepley . loff    - The local offset of each field
7612a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
761305586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
761405586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
761505586334SMatthew G. Knepley 
761605586334SMatthew G. Knepley   Output Parameter:
761705586334SMatthew G. Knepley . indices - Indices for dofs on this point
761805586334SMatthew G. Knepley 
761905586334SMatthew G. Knepley   Level: developer
762005586334SMatthew G. Knepley 
762105586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
762205586334SMatthew G. Knepley */
7623d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7624d71ae5a4SJacob Faibussowitsch {
7625e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
7626552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
7627552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7628552f7358SJed Brown   PetscInt        cind = 0, k;
7629552f7358SJed Brown 
7630552f7358SJed Brown   PetscFunctionBegin;
763108401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
76329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
76339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7634552f7358SJed Brown   if (!cdof || setBC) {
763505586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
763605586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
763705586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
763805586334SMatthew G. Knepley 
763905586334SMatthew G. Knepley       indices[ind] = off + k;
7640552f7358SJed Brown     }
7641552f7358SJed Brown   } else {
76429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
76434acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
764405586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
764505586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
764605586334SMatthew G. Knepley 
76474acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
76484acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
764905586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
76504acb8e1eSToby Isaac         ++cind;
76514acb8e1eSToby Isaac       } else {
765236fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
7653552f7358SJed Brown       }
7654552f7358SJed Brown     }
7655552f7358SJed Brown   }
7656e6ccafaeSMatthew G Knepley   *loff += dof;
76573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7658552f7358SJed Brown }
7659552f7358SJed Brown 
76607e29afd2SMatthew G. Knepley /*
766136fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
76627e29afd2SMatthew G. Knepley 
766336fa2b79SJed Brown  Input Parameters:
766436fa2b79SJed Brown + section - a section (global or local)
766520f4b53cSBarry Smith - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
766636fa2b79SJed Brown . point - point within section
766736fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
766836fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
766936fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
767036fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
767136fa2b79SJed Brown . permsoff - offset
767236fa2b79SJed Brown - indperm - index permutation
767336fa2b79SJed Brown 
767436fa2b79SJed Brown  Output Parameter:
767536fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
767636fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
767736fa2b79SJed Brown 
767836fa2b79SJed Brown  Notes:
767936fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
768036fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
768136fa2b79SJed Brown  in the local vector.
768236fa2b79SJed Brown 
768336fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
768436fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
768536fa2b79SJed Brown 
768636fa2b79SJed Brown  Developer Note:
768736fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
768836fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
768936fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
769036fa2b79SJed Brown 
769136fa2b79SJed Brown  Example:
769236fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
769336fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
769436fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
769536fa2b79SJed 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.
769636fa2b79SJed Brown 
769736fa2b79SJed Brown  Level: developer
76987e29afd2SMatthew G. Knepley */
7699d71ae5a4SJacob 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[])
7700d71ae5a4SJacob Faibussowitsch {
7701552f7358SJed Brown   PetscInt numFields, foff, f;
7702552f7358SJed Brown 
7703552f7358SJed Brown   PetscFunctionBegin;
770408401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
77059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7706552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
77074acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
7708552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
77094acb8e1eSToby Isaac     PetscInt        cind = 0, b;
77104acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7711552f7358SJed Brown 
77129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
77139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7714552f7358SJed Brown     if (!cfdof || setBC) {
771505586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
771605586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
771705586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
771805586334SMatthew G. Knepley 
771905586334SMatthew G. Knepley         indices[ind] = off + foff + b;
772005586334SMatthew G. Knepley       }
7721552f7358SJed Brown     } else {
77229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
772305586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
772405586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
772505586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
772605586334SMatthew G. Knepley 
77274acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
772805586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
7729552f7358SJed Brown           ++cind;
7730552f7358SJed Brown         } else {
773136fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7732552f7358SJed Brown         }
7733552f7358SJed Brown       }
7734552f7358SJed Brown     }
773536fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7736552f7358SJed Brown     foffs[f] += fdof;
7737552f7358SJed Brown   }
77383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7739552f7358SJed Brown }
7740552f7358SJed Brown 
77417e29afd2SMatthew G. Knepley /*
77427e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
77437e29afd2SMatthew G. Knepley 
77447e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7745645102dcSJed Brown 
7746645102dcSJed Brown  Notes:
7747645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7748645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
77497e29afd2SMatthew G. Knepley */
7750d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7751d71ae5a4SJacob Faibussowitsch {
77527e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
77537e29afd2SMatthew G. Knepley 
77547e29afd2SMatthew G. Knepley   PetscFunctionBegin;
77559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
77567e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
77577e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
77587e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
77597e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
77607e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
77617e29afd2SMatthew G. Knepley 
77629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
77639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
77649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7765645102dcSJed Brown     if (!cfdof) {
776605586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
776705586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
776805586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
776905586334SMatthew G. Knepley 
777005586334SMatthew G. Knepley         indices[ind] = foff + b;
777105586334SMatthew G. Knepley       }
77727e29afd2SMatthew G. Knepley     } else {
77739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
777405586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
777505586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
777605586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
777705586334SMatthew G. Knepley 
77787e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
777905586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
77807e29afd2SMatthew G. Knepley           ++cind;
77817e29afd2SMatthew G. Knepley         } else {
778205586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
77837e29afd2SMatthew G. Knepley         }
77847e29afd2SMatthew G. Knepley       }
77857e29afd2SMatthew G. Knepley     }
77867e29afd2SMatthew G. Knepley     foffs[f] += fdof;
77877e29afd2SMatthew G. Knepley   }
77883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
77897e29afd2SMatthew G. Knepley }
77907e29afd2SMatthew G. Knepley 
7791c789d87fSToby Isaac static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms)
7792c789d87fSToby Isaac {
7793c789d87fSToby Isaac   PetscInt numFields, sStart, sEnd, cStart, cEnd;
7794c789d87fSToby Isaac 
7795c789d87fSToby Isaac   PetscFunctionBegin;
7796c789d87fSToby Isaac   PetscCall(PetscSectionGetNumFields(section, &numFields));
7797c789d87fSToby Isaac   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7798c789d87fSToby Isaac   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7799c789d87fSToby Isaac   for (PetscInt p = 0; p < nPoints; p++) {
7800c789d87fSToby Isaac     PetscInt     b       = pnts[2 * p];
7801c789d87fSToby Isaac     PetscInt     bSecDof = 0, bOff;
7802c789d87fSToby Isaac     PetscInt     cSecDof = 0;
7803c789d87fSToby Isaac     PetscSection indices_section;
7804c789d87fSToby Isaac 
7805c789d87fSToby Isaac     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7806c789d87fSToby Isaac     if (!bSecDof) continue;
7807c789d87fSToby Isaac     if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof));
7808c789d87fSToby Isaac     indices_section = cSecDof > 0 ? cSec : section;
7809c789d87fSToby Isaac     if (numFields) {
7810c789d87fSToby Isaac       PetscInt fStart[32], fEnd[32];
7811c789d87fSToby Isaac 
7812c789d87fSToby Isaac       fStart[0] = 0;
7813c789d87fSToby Isaac       fEnd[0]   = 0;
7814c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7815c789d87fSToby Isaac         PetscInt fDof = 0;
7816c789d87fSToby Isaac 
7817c789d87fSToby Isaac         PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof));
7818c789d87fSToby Isaac         fStart[f + 1] = fStart[f] + fDof;
7819c789d87fSToby Isaac         fEnd[f + 1]   = fStart[f + 1];
7820c789d87fSToby Isaac       }
7821c789d87fSToby Isaac       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7822c789d87fSToby Isaac       // only apply permutations on one side
7823c789d87fSToby Isaac       PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices));
7824c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7825ac530a7eSPierre Jolivet         for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7826c789d87fSToby Isaac       }
7827c789d87fSToby Isaac     } else {
7828c789d87fSToby Isaac       PetscInt bEnd = 0;
7829c789d87fSToby Isaac 
7830c789d87fSToby Isaac       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7831c789d87fSToby Isaac       PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices));
7832c789d87fSToby Isaac 
7833c789d87fSToby Isaac       for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7834c789d87fSToby Isaac     }
7835c789d87fSToby Isaac   }
7836c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
7837c789d87fSToby Isaac }
7838c789d87fSToby Isaac 
7839c789d87fSToby 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[])
7840d71ae5a4SJacob Faibussowitsch {
7841d3d1a6afSToby Isaac   Mat             cMat;
7842d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7843d3d1a6afSToby Isaac   IS              aIS;
7844d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7845a19ea1e9SMatthew G. Knepley   PetscInt        sStart = -1, sEnd = -1;
7846a19ea1e9SMatthew G. Knepley   PetscInt        cStart = -1, cEnd = -1;
7847d3d1a6afSToby Isaac   const PetscInt *anchors;
7848e969e7a5SJose E. Roman   PetscInt        numFields, p;
7849d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7850c789d87fSToby Isaac   PetscInt       *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices;
7851c789d87fSToby Isaac   PetscInt        oldOffsets[32];
7852d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7853c789d87fSToby Isaac   PetscInt        oldOffsetsCopy[32];
7854c789d87fSToby Isaac   PetscInt        newOffsetsCopy[32];
7855c789d87fSToby Isaac   PetscScalar    *modMat         = NULL;
7856d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7857d3d1a6afSToby Isaac 
7858d3d1a6afSToby Isaac   PetscFunctionBegin;
7859d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7860d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
78619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7862d3d1a6afSToby Isaac 
78639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7864d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7865d3d1a6afSToby Isaac   if (aSec) {
78669566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
7867c789d87fSToby Isaac     PetscCall(PetscArrayzero(oldOffsets, 32));
78689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
78699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7870a19ea1e9SMatthew G. Knepley     PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7871d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7872d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7873d3d1a6afSToby Isaac      * into the global matrix anyway) */
7874d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7875d3d1a6afSToby Isaac       PetscInt b    = points[p];
7876a19ea1e9SMatthew G. Knepley       PetscInt bDof = 0, bSecDof = 0;
7877d3d1a6afSToby Isaac 
7878a19ea1e9SMatthew G. Knepley       if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7879ad540459SPierre Jolivet       if (!bSecDof) continue;
7880c789d87fSToby Isaac 
7881c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7882c789d87fSToby Isaac         PetscInt fDof = 0;
7883c789d87fSToby Isaac 
7884c789d87fSToby Isaac         PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7885c789d87fSToby Isaac         oldOffsets[f + 1] += fDof;
7886c789d87fSToby Isaac       }
788748a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7888d3d1a6afSToby Isaac       if (bDof) {
7889d3d1a6afSToby Isaac         /* this point is constrained */
7890d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7891d3d1a6afSToby Isaac         PetscInt bOff, q;
7892d3d1a6afSToby Isaac 
78939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7894d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7895d3d1a6afSToby Isaac           PetscInt a    = anchors[bOff + q];
7896a19ea1e9SMatthew G. Knepley           PetscInt aDof = 0;
7897d3d1a6afSToby Isaac 
7898a19ea1e9SMatthew G. Knepley           if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7899c789d87fSToby Isaac           if (aDof) {
7900c789d87fSToby Isaac             anyConstrained = PETSC_TRUE;
7901c789d87fSToby Isaac             newNumPoints += 1;
7902c789d87fSToby Isaac           }
7903d3d1a6afSToby Isaac           newNumIndices += aDof;
7904e969e7a5SJose E. Roman           for (PetscInt f = 0; f < numFields; ++f) {
7905a19ea1e9SMatthew G. Knepley             PetscInt fDof = 0;
7906d3d1a6afSToby Isaac 
7907a19ea1e9SMatthew G. Knepley             if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7908d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7909d3d1a6afSToby Isaac           }
7910d3d1a6afSToby Isaac         }
79119371c9d4SSatish Balay       } else {
7912d3d1a6afSToby Isaac         /* this point is not constrained */
7913d3d1a6afSToby Isaac         newNumPoints++;
79144b2f2278SToby Isaac         newNumIndices += bSecDof;
7915e969e7a5SJose E. Roman         for (PetscInt f = 0; f < numFields; ++f) {
7916d3d1a6afSToby Isaac           PetscInt fDof;
7917d3d1a6afSToby Isaac 
79189566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7919d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7920d3d1a6afSToby Isaac         }
7921d3d1a6afSToby Isaac       }
7922d3d1a6afSToby Isaac     }
7923d3d1a6afSToby Isaac   }
7924d3d1a6afSToby Isaac   if (!anyConstrained) {
792572b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
792672b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
792772b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
7928c789d87fSToby Isaac     if (outMat) *outMat = NULL;
79299566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
79303ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7931d3d1a6afSToby Isaac   }
7932d3d1a6afSToby Isaac 
79336ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
79346ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
79356ecaa68aSToby Isaac 
7936e969e7a5SJose E. Roman   for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7937e969e7a5SJose E. Roman   for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f];
7938d3d1a6afSToby Isaac 
7939c789d87fSToby Isaac   if (!outPoints && !outMat) {
79406ecaa68aSToby Isaac     if (offsets) {
7941e969e7a5SJose E. Roman       for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
79426ecaa68aSToby Isaac     }
79439566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
79443ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
79456ecaa68aSToby Isaac   }
79466ecaa68aSToby Isaac 
79471dca8a05SBarry 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);
7948c789d87fSToby 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);
7949d3d1a6afSToby Isaac 
79509566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7951a19ea1e9SMatthew G. Knepley   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7952d3d1a6afSToby Isaac 
79536ecaa68aSToby Isaac   /* output arrays */
79549566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7955c789d87fSToby Isaac   PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints));
79566ecaa68aSToby Isaac 
7957c789d87fSToby Isaac   // get the new Points
7958c789d87fSToby Isaac   for (PetscInt p = 0, newP = 0; p < numPoints; p++) {
7959d3d1a6afSToby Isaac     PetscInt b    = points[2 * p];
7960c789d87fSToby Isaac     PetscInt bDof = 0, bSecDof = 0, bOff;
7961d3d1a6afSToby Isaac 
7962a19ea1e9SMatthew G. Knepley     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7963ad540459SPierre Jolivet     if (!bSecDof) continue;
796448a46eb9SPierre Jolivet     if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7965d3d1a6afSToby Isaac     if (bDof) {
79669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7967c789d87fSToby Isaac       for (PetscInt q = 0; q < bDof; q++) {
7968a19ea1e9SMatthew G. Knepley         PetscInt a = anchors[bOff + q], aDof = 0;
7969d3d1a6afSToby Isaac 
7970a19ea1e9SMatthew G. Knepley         if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7971c789d87fSToby Isaac         if (aDof) {
7972c789d87fSToby Isaac           newPoints[2 * newP]     = a;
7973c789d87fSToby Isaac           newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation
7974d3d1a6afSToby Isaac           newP++;
7975d3d1a6afSToby Isaac         }
7976d3d1a6afSToby Isaac       }
7977d3d1a6afSToby Isaac     } else {
7978d3d1a6afSToby Isaac       newPoints[2 * newP]     = b;
7979c789d87fSToby Isaac       newPoints[2 * newP + 1] = points[2 * p + 1];
7980d3d1a6afSToby Isaac       newP++;
7981d3d1a6afSToby Isaac     }
7982d3d1a6afSToby Isaac   }
7983d3d1a6afSToby Isaac 
7984c789d87fSToby Isaac   if (outMat) {
7985c789d87fSToby Isaac     PetscScalar *tmpMat;
7986c789d87fSToby Isaac     PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32));
7987c789d87fSToby Isaac     PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32));
7988c789d87fSToby Isaac 
7989c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices));
7990c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7991c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7992c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7993c789d87fSToby Isaac 
7994c789d87fSToby Isaac     for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1;
7995c789d87fSToby Isaac     for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1;
7996c789d87fSToby Isaac 
7997c789d87fSToby Isaac     PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms));
7998c789d87fSToby Isaac     PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL));
7999c789d87fSToby Isaac 
8000c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
8001c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
8002c789d87fSToby Isaac     PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices));
8003c789d87fSToby Isaac     // for each field, insert the anchor modification into modMat
8004c789d87fSToby Isaac     for (PetscInt f = 0; f < PetscMax(1, numFields); f++) {
8005c789d87fSToby Isaac       PetscInt fStart    = oldOffsets[f];
8006c789d87fSToby Isaac       PetscInt fNewStart = newOffsets[f];
8007e60de12fSPierre Jolivet       for (PetscInt p = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) {
8008c789d87fSToby Isaac         PetscInt b    = points[2 * p];
8009c789d87fSToby Isaac         PetscInt bDof = 0, bSecDof = 0, bOff;
8010c789d87fSToby Isaac 
8011c789d87fSToby Isaac         if (b >= sStart && b < sEnd) {
8012d3d1a6afSToby Isaac           if (numFields) {
8013c789d87fSToby Isaac             PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof));
80149371c9d4SSatish Balay           } else {
8015c789d87fSToby Isaac             PetscCall(PetscSectionGetDof(section, b, &bSecDof));
8016d3d1a6afSToby Isaac           }
8017d3d1a6afSToby Isaac         }
8018c789d87fSToby Isaac         if (!bSecDof) continue;
8019c789d87fSToby Isaac         if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
8020c789d87fSToby Isaac         if (bDof) {
8021c789d87fSToby Isaac           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
8022e60de12fSPierre Jolivet           for (PetscInt q = 0; q < bDof; q++) {
8023c789d87fSToby Isaac             PetscInt a = anchors[bOff + q], aDof = 0;
8024d3d1a6afSToby Isaac 
8025c789d87fSToby Isaac             if (a >= sStart && a < sEnd) {
8026d3d1a6afSToby Isaac               if (numFields) {
8027c789d87fSToby Isaac                 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
8028c789d87fSToby Isaac               } else {
8029c789d87fSToby Isaac                 PetscCall(PetscSectionGetDof(section, a, &aDof));
8030d3d1a6afSToby Isaac               }
8031d3d1a6afSToby Isaac             }
8032c789d87fSToby Isaac             if (aDof) {
8033c789d87fSToby Isaac               PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat));
8034c789d87fSToby Isaac               for (PetscInt d = 0; d < bSecDof; d++) {
8035c789d87fSToby Isaac                 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e];
8036c789d87fSToby Isaac               }
8037c789d87fSToby Isaac             }
8038c789d87fSToby Isaac             oNew += aDof;
8039c789d87fSToby Isaac           }
80409371c9d4SSatish Balay         } else {
8041c789d87fSToby Isaac           // Insert the identity matrix in this block
8042c789d87fSToby Isaac           for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1;
8043c789d87fSToby Isaac           oNew += bSecDof;
8044d3d1a6afSToby Isaac         }
8045c789d87fSToby Isaac         o += bSecDof;
8046d3d1a6afSToby Isaac       }
8047d3d1a6afSToby Isaac     }
8048d3d1a6afSToby Isaac 
8049c789d87fSToby Isaac     *outMat = modMat;
80506ecaa68aSToby Isaac 
8051c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
8052c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
8053c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
8054c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
8055c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices));
8056d3d1a6afSToby Isaac   }
80579566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
8058d3d1a6afSToby Isaac 
8059d3d1a6afSToby Isaac   /* output */
80606ecaa68aSToby Isaac   if (outPoints) {
8061d3d1a6afSToby Isaac     *outPoints = newPoints;
80629371c9d4SSatish Balay   } else {
80639566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
80646ecaa68aSToby Isaac   }
8065e969e7a5SJose E. Roman   for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
80663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8067d3d1a6afSToby Isaac }
8068d3d1a6afSToby Isaac 
8069c789d87fSToby 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)
8070c789d87fSToby Isaac {
8071c789d87fSToby Isaac   PetscScalar *modMat        = NULL;
8072c789d87fSToby Isaac   PetscInt     newNumIndices = -1;
80737cd05799SMatthew G. Knepley 
8074c789d87fSToby Isaac   PetscFunctionBegin;
8075c789d87fSToby 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.
8076c789d87fSToby Isaac      modMat is that matrix C */
8077c789d87fSToby Isaac   PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL));
8078c789d87fSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
8079c789d87fSToby Isaac   if (modMat) {
8080c789d87fSToby Isaac     const PetscScalar *newValues = values;
80817cd05799SMatthew G. Knepley 
8082c789d87fSToby Isaac     if (multiplyRight) {
8083c789d87fSToby Isaac       PetscScalar *newNewValues = NULL;
80846497c311SBarry Smith       PetscBLASInt M, N, K;
8085c789d87fSToby Isaac       PetscScalar  a = 1.0, b = 0.0;
80867cd05799SMatthew G. Knepley 
8087c789d87fSToby 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);
80887cd05799SMatthew G. Knepley 
80896497c311SBarry Smith       PetscCall(PetscBLASIntCast(newNumIndices, &M));
80906497c311SBarry Smith       PetscCall(PetscBLASIntCast(numRows, &N));
80916497c311SBarry Smith       PetscCall(PetscBLASIntCast(numIndices, &K));
8092c789d87fSToby Isaac       PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues));
8093c789d87fSToby Isaac       // row-major to column-major conversion, right multiplication becomes left multiplication
8094c789d87fSToby Isaac       PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M));
8095c789d87fSToby Isaac       numCols   = newNumIndices;
8096c789d87fSToby Isaac       newValues = newNewValues;
8097c789d87fSToby Isaac     }
8098a1cb98faSBarry Smith 
8099c789d87fSToby Isaac     if (multiplyLeft) {
8100c789d87fSToby Isaac       PetscScalar *newNewValues = NULL;
81016497c311SBarry Smith       PetscBLASInt M, N, K;
8102c789d87fSToby Isaac       PetscScalar  a = 1.0, b = 0.0;
81037cd05799SMatthew G. Knepley 
8104c789d87fSToby 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);
8105c789d87fSToby Isaac 
81066497c311SBarry Smith       PetscCall(PetscBLASIntCast(numCols, &M));
81076497c311SBarry Smith       PetscCall(PetscBLASIntCast(newNumIndices, &N));
81086497c311SBarry Smith       PetscCall(PetscBLASIntCast(numIndices, &K));
8109c789d87fSToby Isaac       PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues));
8110c789d87fSToby Isaac       // row-major to column-major conversion, left multiplication becomes right multiplication
8111c789d87fSToby Isaac       PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M));
8112c789d87fSToby Isaac       if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues));
8113c789d87fSToby Isaac       newValues = newNewValues;
8114c789d87fSToby Isaac     }
8115c789d87fSToby Isaac     *outValues = (PetscScalar *)newValues;
8116c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
8117c789d87fSToby Isaac   }
8118c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
8119c789d87fSToby Isaac }
8120c789d87fSToby Isaac 
8121c789d87fSToby 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)
8122c789d87fSToby Isaac {
8123c789d87fSToby Isaac   PetscFunctionBegin;
8124c789d87fSToby Isaac   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft));
8125c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
8126c789d87fSToby Isaac }
8127c789d87fSToby Isaac 
8128c789d87fSToby Isaac static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize)
8129c789d87fSToby Isaac {
8130c789d87fSToby Isaac   /* Closure ordering */
8131c789d87fSToby Isaac   PetscSection    clSection;
8132c789d87fSToby Isaac   IS              clPoints;
8133c789d87fSToby Isaac   const PetscInt *clp;
8134c789d87fSToby Isaac   PetscInt       *points;
8135c789d87fSToby Isaac   PetscInt        Ncl, Ni = 0;
8136c789d87fSToby Isaac 
8137c789d87fSToby Isaac   PetscFunctionBeginHot;
8138c789d87fSToby Isaac   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
8139c789d87fSToby Isaac   for (PetscInt p = 0; p < Ncl * 2; p += 2) {
8140c789d87fSToby Isaac     PetscInt dof;
8141c789d87fSToby Isaac 
8142c789d87fSToby Isaac     PetscCall(PetscSectionGetDof(section, points[p], &dof));
8143c789d87fSToby Isaac     Ni += dof;
8144c789d87fSToby Isaac   }
8145c789d87fSToby Isaac   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
8146c789d87fSToby Isaac   *closureSize = Ni;
8147c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
8148c789d87fSToby Isaac }
8149c789d87fSToby Isaac 
8150c789d87fSToby 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)
8151d71ae5a4SJacob Faibussowitsch {
815271f0bbf9SMatthew G. Knepley   /* Closure ordering */
81537773e69fSMatthew G. Knepley   PetscSection    clSection;
81547773e69fSMatthew G. Knepley   IS              clPoints;
815571f0bbf9SMatthew G. Knepley   const PetscInt *clp;
815671f0bbf9SMatthew G. Knepley   PetscInt       *points;
815771f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
815871f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
81594acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
816071f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
816171f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
816271f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
816371f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
816471f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
816571f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
816671f0bbf9SMatthew G. Knepley 
816771f0bbf9SMatthew G. Knepley   PetscInt *idx;
816871f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
816971f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
81707caea556SToby Isaac   PetscInt  idxStart, idxEnd;
8171c789d87fSToby Isaac   PetscInt  nRows, nCols;
81727773e69fSMatthew G. Knepley 
817371f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
81747773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81757773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
817636fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
8177c789d87fSToby Isaac   PetscAssertPointer(numRows, 6);
8178c789d87fSToby Isaac   PetscAssertPointer(numCols, 7);
8179c789d87fSToby Isaac   if (indices) PetscAssertPointer(indices, 8);
8180c789d87fSToby Isaac   if (outOffsets) PetscAssertPointer(outOffsets, 9);
8181c789d87fSToby Isaac   if (values) PetscAssertPointer(values, 10);
81829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
818363a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
81849566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
818571f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
818607218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
8187c459fbc1SJed Brown   if (useClPerm) {
8188c459fbc1SJed Brown     PetscInt depth, clsize;
81899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
8190c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
8191c459fbc1SJed Brown       PetscInt dof;
81929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
8193c459fbc1SJed Brown       clsize += dof;
8194c459fbc1SJed Brown     }
81959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
8196c459fbc1SJed Brown   }
819771f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
819871f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
81997773e69fSMatthew G. Knepley     PetscInt dof, fdof;
82007773e69fSMatthew G. Knepley 
82019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
82027773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
82039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
82047773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
82057773e69fSMatthew G. Knepley     }
820671f0bbf9SMatthew G. Knepley     Ni += dof;
82077773e69fSMatthew G. Knepley   }
8208c789d87fSToby Isaac   if (*numRows == -1) *numRows = Ni;
8209c789d87fSToby Isaac   if (*numCols == -1) *numCols = Ni;
8210c789d87fSToby Isaac   nRows = *numRows;
8211c789d87fSToby Isaac   nCols = *numCols;
82127773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
82131dca8a05SBarry 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);
821471f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
8215c789d87fSToby Isaac   if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols);
8216c789d87fSToby Isaac   if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows);
821771f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
82189566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
82199566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
822071f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
822171f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
822271f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
82236ecaa68aSToby Isaac 
822471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
822571f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
822671f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
822771f0bbf9SMatthew G. Knepley 
82289566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
82299566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
823071f0bbf9SMatthew G. Knepley         if (flip) {
823171f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
823271f0bbf9SMatthew G. Knepley 
823371f0bbf9SMatthew G. Knepley           if (!valCopy) {
82349566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
823571f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
823671f0bbf9SMatthew G. Knepley             *values = valCopy;
823771f0bbf9SMatthew G. Knepley           }
823871f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
823971f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
824071f0bbf9SMatthew G. Knepley 
8241c789d87fSToby Isaac             if (multiplyRight) {
8242ac530a7eSPierre Jolivet               for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval;
8243c789d87fSToby Isaac             }
8244c789d87fSToby Isaac             if (multiplyLeft) {
8245ac530a7eSPierre Jolivet               for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval;
82466ecaa68aSToby Isaac             }
82476ecaa68aSToby Isaac           }
824871f0bbf9SMatthew G. Knepley         }
824971f0bbf9SMatthew G. Knepley         foffset += fdof;
825071f0bbf9SMatthew G. Knepley       }
825171f0bbf9SMatthew G. Knepley     }
825271f0bbf9SMatthew G. Knepley   }
825371f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
8254c789d87fSToby Isaac   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft));
825571f0bbf9SMatthew G. Knepley   if (NclC) {
825663bfac88SBarry Smith     if (multiplyRight) *numCols = NiC;
825763bfac88SBarry Smith     if (multiplyLeft) *numRows = NiC;
82589566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
825971f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
82609566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
82619566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
826271f0bbf9SMatthew G. Knepley     }
826371f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
82649566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
82659566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
826671f0bbf9SMatthew G. Knepley     }
82679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
826871f0bbf9SMatthew G. Knepley     Ncl    = NclC;
826971f0bbf9SMatthew G. Knepley     Ni     = NiC;
827071f0bbf9SMatthew G. Knepley     points = pointsC;
827171f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
827271f0bbf9SMatthew G. Knepley   }
827371f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
82749566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
82757caea556SToby Isaac   PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd));
827671f0bbf9SMatthew G. Knepley   if (Nf) {
827771f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
827871f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
827971f0bbf9SMatthew G. Knepley 
82809371c9d4SSatish Balay     if (outOffsets) {
82819371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
82829371c9d4SSatish Balay     }
82839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
828471f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
828571f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
828671f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
828771f0bbf9SMatthew G. Knepley 
82889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
82897773e69fSMatthew G. Knepley       }
82907773e69fSMatthew G. Knepley     } else {
829171f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
829271f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
829371f0bbf9SMatthew G. Knepley 
82947caea556SToby Isaac         if (pnt < idxStart || pnt >= idxEnd) continue;
82959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
829671f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
829771f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
829871f0bbf9SMatthew G. Knepley          * global section. */
82999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
830071f0bbf9SMatthew G. Knepley       }
830171f0bbf9SMatthew G. Knepley     }
830271f0bbf9SMatthew G. Knepley   } else {
830371f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
830471f0bbf9SMatthew G. Knepley 
830571f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
830671f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
83074acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
83084acb8e1eSToby Isaac 
83097caea556SToby Isaac       if (pnt < idxStart || pnt >= idxEnd) continue;
83109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
831171f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
831271f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
83139566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
83147773e69fSMatthew G. Knepley     }
83157773e69fSMatthew G. Knepley   }
831671f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
831771f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
83189566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
83199566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
83204acb8e1eSToby Isaac   }
832171f0bbf9SMatthew G. Knepley   if (NclC) {
83229566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
83237773e69fSMatthew G. Knepley   } else {
83249566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
83257773e69fSMatthew G. Knepley   }
832671f0bbf9SMatthew G. Knepley 
832771f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
83283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83297773e69fSMatthew G. Knepley }
83307773e69fSMatthew G. Knepley 
8331d3d1a6afSToby Isaac /*@C
8332d3d1a6afSToby Isaac   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
8333d3d1a6afSToby Isaac 
8334d3d1a6afSToby Isaac   Not collective
8335d3d1a6afSToby Isaac 
8336d3d1a6afSToby Isaac   Input Parameters:
8337d3d1a6afSToby Isaac + dm         - The `DM`
8338d3d1a6afSToby Isaac . section    - The `PetscSection` describing the points (a local section)
8339d3d1a6afSToby Isaac . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
8340d3d1a6afSToby Isaac . point      - The point defining the closure
8341d3d1a6afSToby Isaac - useClPerm  - Use the closure point permutation if available
8342d3d1a6afSToby Isaac 
8343d3d1a6afSToby Isaac   Output Parameters:
8344d3d1a6afSToby Isaac + numIndices - The number of dof indices in the closure of point with the input sections
8345d3d1a6afSToby Isaac . indices    - The dof indices
8346c3871b17SNoam T . outOffsets - Array, of length the number of fields plus 1, to write the field offsets into, or `NULL`
8347d3d1a6afSToby Isaac - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
8348d3d1a6afSToby Isaac 
8349d3d1a6afSToby Isaac   Level: advanced
8350d3d1a6afSToby Isaac 
8351d3d1a6afSToby Isaac   Notes:
83522c9a7b26SBarry Smith   Call `DMPlexRestoreClosureIndices()` to free allocated memory
8353d3d1a6afSToby Isaac 
8354d3d1a6afSToby Isaac   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
8355d3d1a6afSToby Isaac   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
8356d3d1a6afSToby Isaac   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
8357d3d1a6afSToby Isaac   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
8358d3d1a6afSToby Isaac   indices (with the above semantics) are implied.
8359d3d1a6afSToby Isaac 
8360d3d1a6afSToby Isaac .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
8361d3d1a6afSToby Isaac           `PetscSection`, `DMGetGlobalSection()`
8362d3d1a6afSToby Isaac @*/
8363ce78bad3SBarry Smith PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[])
8364d3d1a6afSToby Isaac {
8365c789d87fSToby Isaac   PetscInt numRows = -1, numCols = -1;
8366d3d1a6afSToby Isaac 
8367d3d1a6afSToby Isaac   PetscFunctionBeginHot;
8368c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE));
8369c789d87fSToby Isaac   PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols);
8370c789d87fSToby Isaac   *numIndices = numRows;
83717773e69fSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
83727773e69fSMatthew G. Knepley }
83737773e69fSMatthew G. Knepley 
83747cd05799SMatthew G. Knepley /*@C
837571f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
83767cd05799SMatthew G. Knepley 
83777cd05799SMatthew G. Knepley   Not collective
83787cd05799SMatthew G. Knepley 
83797cd05799SMatthew G. Knepley   Input Parameters:
8380a1cb98faSBarry Smith + dm         - The `DM`
8381a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
8382a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
838371f0bbf9SMatthew G. Knepley . point      - The point defining the closure
838471f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
838571f0bbf9SMatthew G. Knepley 
838671f0bbf9SMatthew G. Knepley   Output Parameters:
838771f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
838871f0bbf9SMatthew G. Knepley . indices    - The dof indices
838920f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
839020f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
839171f0bbf9SMatthew G. Knepley 
8392a1cb98faSBarry Smith   Level: advanced
839371f0bbf9SMatthew G. Knepley 
8394a1cb98faSBarry Smith   Notes:
8395a1cb98faSBarry Smith   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
8396a1cb98faSBarry Smith 
8397a1cb98faSBarry Smith   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
839871f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
839971f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
840071f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
840171f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
84027cd05799SMatthew G. Knepley 
84031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
84047cd05799SMatthew G. Knepley @*/
8405ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[])
8406d71ae5a4SJacob Faibussowitsch {
84077773e69fSMatthew G. Knepley   PetscFunctionBegin;
84087773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84094f572ea9SToby Isaac   PetscAssertPointer(indices, 7);
84109566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
84113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84127773e69fSMatthew G. Knepley }
84137773e69fSMatthew G. Knepley 
8414e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8415d71ae5a4SJacob Faibussowitsch {
8416552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
8417552f7358SJed Brown   PetscInt          *indices;
841871f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
841971f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
8420552f7358SJed Brown   PetscErrorCode     ierr;
8421552f7358SJed Brown 
8422552f7358SJed Brown   PetscFunctionBegin;
8423552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
84249566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
84253dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
84269566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
84273dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
8428e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 5);
8429552f7358SJed Brown 
8430e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
84310d644c17SKarl Rupp 
84329566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
8433d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
84344a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8435552f7358SJed Brown   if (ierr) {
8436552f7358SJed Brown     PetscMPIInt rank;
8437552f7358SJed Brown 
84389566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
84399566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
84409566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
84419566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
84429566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8443c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
8444552f7358SJed Brown   }
84454a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
84464a1e0b3eSMatthew G. Knepley     PetscInt i;
84479566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
844863a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
84499566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
84504a1e0b3eSMatthew G. Knepley   }
845171f0bbf9SMatthew G. Knepley 
84529566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
84539566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
84543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84554acb8e1eSToby Isaac }
845671f0bbf9SMatthew G. Knepley 
84574a1e0b3eSMatthew G. Knepley /*@C
8458e8e188d2SZach Atkins   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
8459e8e188d2SZach Atkins 
8460e8e188d2SZach Atkins   Not collective
8461e8e188d2SZach Atkins 
8462e8e188d2SZach Atkins   Input Parameters:
8463e8e188d2SZach Atkins + dm            - The `DM`
8464e8e188d2SZach Atkins . section       - The section describing the layout in `v`, or `NULL` to use the default section
8465e8e188d2SZach Atkins . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
8466e8e188d2SZach Atkins . A             - The matrix
8467e8e188d2SZach Atkins . point         - The point in the `DM`
8468e8e188d2SZach Atkins . values        - The array of values
8469e8e188d2SZach Atkins - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8470e8e188d2SZach Atkins 
8471e8e188d2SZach Atkins   Level: intermediate
8472e8e188d2SZach Atkins 
8473e8e188d2SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8474e8e188d2SZach Atkins @*/
8475e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8476e8e188d2SZach Atkins {
8477e8e188d2SZach Atkins   PetscFunctionBegin;
8478e8e188d2SZach Atkins   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
8479e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
8480e8e188d2SZach Atkins }
8481e8e188d2SZach Atkins 
8482e8e188d2SZach Atkins /*@C
848360225df5SJacob Faibussowitsch   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
84844a1e0b3eSMatthew G. Knepley 
84854a1e0b3eSMatthew G. Knepley   Not collective
84864a1e0b3eSMatthew G. Knepley 
84874a1e0b3eSMatthew G. Knepley   Input Parameters:
8488a1cb98faSBarry Smith + dmRow            - The `DM` for the row fields
848920f4b53cSBarry Smith . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
8490e8e188d2SZach Atkins . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
849120f4b53cSBarry Smith . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
8492a1cb98faSBarry Smith . dmCol            - The `DM` for the column fields
849320f4b53cSBarry Smith . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
8494e8e188d2SZach Atkins . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
849520f4b53cSBarry Smith . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
84964a1e0b3eSMatthew G. Knepley . A                - The matrix
8497a1cb98faSBarry Smith . point            - The point in the `DM`
84984a1e0b3eSMatthew G. Knepley . values           - The array of values
8499a1cb98faSBarry Smith - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
85004a1e0b3eSMatthew G. Knepley 
85014a1e0b3eSMatthew G. Knepley   Level: intermediate
85024a1e0b3eSMatthew G. Knepley 
85031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
85044a1e0b3eSMatthew G. Knepley @*/
8505e8e188d2SZach 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)
8506d71ae5a4SJacob Faibussowitsch {
850771f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
850871f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
8509c789d87fSToby Isaac   PetscInt           numIndicesRow = -1, numIndicesCol = -1;
85107caea556SToby Isaac   const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2;
8511c789d87fSToby Isaac 
851271f0bbf9SMatthew G. Knepley   PetscErrorCode ierr;
851371f0bbf9SMatthew G. Knepley 
851471f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
851571f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
85169566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
851771f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
85189566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
851971f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
8520e8e188d2SZach Atkins   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5);
85219566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
8522e8e188d2SZach Atkins   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6);
85239566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
8524e8e188d2SZach Atkins   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7);
8525e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 9);
852671f0bbf9SMatthew G. Knepley 
8527c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow));
8528c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol));
85297caea556SToby Isaac   valuesV1 = valuesV0;
8530c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE));
85317caea556SToby Isaac   valuesV2 = valuesV1;
8532c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE));
853371f0bbf9SMatthew G. Knepley 
8534c789d87fSToby Isaac   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2));
8535d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8536c789d87fSToby Isaac   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode);
853771f0bbf9SMatthew G. Knepley   if (ierr) {
853871f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
853971f0bbf9SMatthew G. Knepley 
85409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
85419566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
85429566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
85437caea556SToby Isaac     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2));
85447caea556SToby Isaac     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
85457caea556SToby Isaac     if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
85467caea556SToby Isaac     if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
8547d3d1a6afSToby Isaac   }
854871f0bbf9SMatthew G. Knepley 
85497caea556SToby Isaac   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2));
85507caea556SToby Isaac   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
85517caea556SToby Isaac   if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
85527caea556SToby Isaac   if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
85533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8554552f7358SJed Brown }
8555552f7358SJed Brown 
8556d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8557d71ae5a4SJacob Faibussowitsch {
8558de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
8559de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8560de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
8561de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
856217c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8563de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
8564412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
85654ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8566de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
8567de41b84cSMatthew G. Knepley 
8568de41b84cSMatthew G. Knepley   PetscFunctionBegin;
8569de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8570de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
85719566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8572de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
85739566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8574de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
85759566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8576de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
85779566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8578de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8579de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
85809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
858163a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
85829566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
85839566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
8584de41b84cSMatthew G. Knepley   /* Column indices */
85859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
85864ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
8587de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
8588de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
85899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8590de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8591de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8592de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
8593de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
8594de41b84cSMatthew G. Knepley       ++q;
8595de41b84cSMatthew G. Knepley     }
8596de41b84cSMatthew G. Knepley   }
8597de41b84cSMatthew G. Knepley   numCPoints = q;
8598de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8599de41b84cSMatthew G. Knepley     PetscInt fdof;
8600de41b84cSMatthew G. Knepley 
86019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
86024ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8603de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
86049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8605de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
8606de41b84cSMatthew G. Knepley     }
8607de41b84cSMatthew G. Knepley     numCIndices += dof;
8608de41b84cSMatthew G. Knepley   }
8609de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8610de41b84cSMatthew G. Knepley   /* Row indices */
86119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8612412e9a14SMatthew G. Knepley   {
8613012bc364SMatthew G. Knepley     DMPlexTransform tr;
8614012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8615012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8616012bc364SMatthew G. Knepley 
86179566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
86189566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
86199566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8620012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
86219566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8622412e9a14SMatthew G. Knepley   }
86239566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8624de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
8625de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
86269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8627de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
86289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8629de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
8630de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
86319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
86324ca5e9f5SMatthew G. Knepley         if (!dof) continue;
86339371c9d4SSatish Balay         for (s = 0; s < q; ++s)
86349371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
86354ca5e9f5SMatthew G. Knepley         if (s < q) continue;
8636de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
8637de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8638de41b84cSMatthew G. Knepley         ++q;
8639de41b84cSMatthew G. Knepley       }
8640de41b84cSMatthew G. Knepley     }
86419566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8642de41b84cSMatthew G. Knepley   }
8643de41b84cSMatthew G. Knepley   numFPoints = q;
8644de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8645de41b84cSMatthew G. Knepley     PetscInt fdof;
8646de41b84cSMatthew G. Knepley 
86479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
86484ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8649de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
86509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8651de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
8652de41b84cSMatthew G. Knepley     }
8653de41b84cSMatthew G. Knepley     numFIndices += dof;
8654de41b84cSMatthew G. Knepley   }
8655de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8656de41b84cSMatthew G. Knepley 
86571dca8a05SBarry 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);
86581dca8a05SBarry 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);
86599566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
86609566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8661de41b84cSMatthew G. Knepley   if (numFields) {
86624acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
86634acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
86644acb8e1eSToby Isaac 
86654acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
86669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
86679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8668de41b84cSMatthew G. Knepley     }
86694acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
86709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
86719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
86724acb8e1eSToby Isaac     }
86734acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
86749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
86759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
86764acb8e1eSToby Isaac     }
86774acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
86789566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
86799566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8680de41b84cSMatthew G. Knepley     }
8681de41b84cSMatthew G. Knepley   } else {
86824acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
86834acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
86844acb8e1eSToby Isaac 
86859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
86869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
86874acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
86884acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
86894acb8e1eSToby Isaac 
86909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
86919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8692de41b84cSMatthew G. Knepley     }
86934acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
86944acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
86954acb8e1eSToby Isaac 
86969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
86979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8698de41b84cSMatthew G. Knepley     }
86999566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
87009566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8701de41b84cSMatthew G. Knepley   }
87029566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
87034acb8e1eSToby Isaac   /* TODO: flips */
8704d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8705de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8706de41b84cSMatthew G. Knepley   if (ierr) {
8707de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8708de41b84cSMatthew G. Knepley 
87099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
87109566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
87119566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
87129566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
87139566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8714de41b84cSMatthew G. Knepley   }
87159566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
87169566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
87179566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
87189566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
87193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8720de41b84cSMatthew G. Knepley }
8721de41b84cSMatthew G. Knepley 
8722d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8723d71ae5a4SJacob Faibussowitsch {
87247c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
87257c927364SMatthew G. Knepley   PetscInt       *cpoints      = NULL;
8726230af79eSStefano Zampini   PetscInt        foffsets[32] = {0}, coffsets[32] = {0};
872717c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8728412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
87297c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
87307c927364SMatthew G. Knepley 
87317c927364SMatthew G. Knepley   PetscFunctionBegin;
87327c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
87337c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
87349566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
87357c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
87369566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
87377c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
87389566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
87397c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
87409566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
87417c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
87429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
874363a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
87447c927364SMatthew G. Knepley   /* Column indices */
87459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
87467c927364SMatthew G. Knepley   maxFPoints = numCPoints;
87477c927364SMatthew G. Knepley   /* Compress out points not in the section */
87487c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
87499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
87507c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
87517c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
87527c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
87537c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
87547c927364SMatthew G. Knepley       ++q;
87557c927364SMatthew G. Knepley     }
87567c927364SMatthew G. Knepley   }
87577c927364SMatthew G. Knepley   numCPoints = q;
87587c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
87597c927364SMatthew G. Knepley     PetscInt fdof;
87607c927364SMatthew G. Knepley 
87619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
87627c927364SMatthew G. Knepley     if (!dof) continue;
87637c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
87649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
87657c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
87667c927364SMatthew G. Knepley     }
87677c927364SMatthew G. Knepley     numCIndices += dof;
87687c927364SMatthew G. Knepley   }
87697c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
87707c927364SMatthew G. Knepley   /* Row indices */
87719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8772412e9a14SMatthew G. Knepley   {
8773012bc364SMatthew G. Knepley     DMPlexTransform tr;
8774012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8775012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8776012bc364SMatthew G. Knepley 
87779566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
87789566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
87799566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8780012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
87819566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8782412e9a14SMatthew G. Knepley   }
87839566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
87847c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
87857c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
87869566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
87877c927364SMatthew G. Knepley     /* Compress out points not in the section */
87889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
87897c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
87907c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
87919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
87927c927364SMatthew G. Knepley         if (!dof) continue;
87939371c9d4SSatish Balay         for (s = 0; s < q; ++s)
87949371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
87957c927364SMatthew G. Knepley         if (s < q) continue;
87967c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
87977c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
87987c927364SMatthew G. Knepley         ++q;
87997c927364SMatthew G. Knepley       }
88007c927364SMatthew G. Knepley     }
88019566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
88027c927364SMatthew G. Knepley   }
88037c927364SMatthew G. Knepley   numFPoints = q;
88047c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
88057c927364SMatthew G. Knepley     PetscInt fdof;
88067c927364SMatthew G. Knepley 
88079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
88087c927364SMatthew G. Knepley     if (!dof) continue;
88097c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
88109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
88117c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
88127c927364SMatthew G. Knepley     }
88137c927364SMatthew G. Knepley     numFIndices += dof;
88147c927364SMatthew G. Knepley   }
88157c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
88167c927364SMatthew G. Knepley 
88171dca8a05SBarry 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);
88181dca8a05SBarry 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);
88197c927364SMatthew G. Knepley   if (numFields) {
88204acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
88214acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
88224acb8e1eSToby Isaac 
88234acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
88249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
88259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
88267c927364SMatthew G. Knepley     }
88274acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
88289566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
88299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
88304acb8e1eSToby Isaac     }
88314acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
88329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
88339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
88344acb8e1eSToby Isaac     }
88354acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
88369566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
88379566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
88387c927364SMatthew G. Knepley     }
88397c927364SMatthew G. Knepley   } else {
88404acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
88414acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
88424acb8e1eSToby Isaac 
88439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
88449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
88454acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
88464acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
88474acb8e1eSToby Isaac 
88489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
88499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
88507c927364SMatthew G. Knepley     }
88514acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
88524acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
88534acb8e1eSToby Isaac 
88549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
88559566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
88567c927364SMatthew G. Knepley     }
88579566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
88589566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
88597c927364SMatthew G. Knepley   }
88609566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
88619566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
88623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
88637c927364SMatthew G. Knepley }
88647c927364SMatthew G. Knepley 
8865cc4c1da9SBarry Smith /*@
88667cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
88677cd05799SMatthew G. Knepley 
88687cd05799SMatthew G. Knepley   Input Parameter:
8869a1cb98faSBarry Smith . dm - The `DMPLEX` object
88707cd05799SMatthew G. Knepley 
88717cd05799SMatthew G. Knepley   Output Parameter:
88727cd05799SMatthew G. Knepley . cellHeight - The height of a cell
88737cd05799SMatthew G. Knepley 
88747cd05799SMatthew G. Knepley   Level: developer
88757cd05799SMatthew G. Knepley 
88761cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
88777cd05799SMatthew G. Knepley @*/
8878d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8879d71ae5a4SJacob Faibussowitsch {
8880552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8881552f7358SJed Brown 
8882552f7358SJed Brown   PetscFunctionBegin;
8883552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88844f572ea9SToby Isaac   PetscAssertPointer(cellHeight, 2);
8885552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
88863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8887552f7358SJed Brown }
8888552f7358SJed Brown 
8889cc4c1da9SBarry Smith /*@
88907cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
88917cd05799SMatthew G. Knepley 
88927cd05799SMatthew G. Knepley   Input Parameters:
8893a1cb98faSBarry Smith + dm         - The `DMPLEX` object
88947cd05799SMatthew G. Knepley - cellHeight - The height of a cell
88957cd05799SMatthew G. Knepley 
88967cd05799SMatthew G. Knepley   Level: developer
88977cd05799SMatthew G. Knepley 
88981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
88997cd05799SMatthew G. Knepley @*/
8900d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8901d71ae5a4SJacob Faibussowitsch {
8902552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8903552f7358SJed Brown 
8904552f7358SJed Brown   PetscFunctionBegin;
8905552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8906552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
89073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8908552f7358SJed Brown }
8909552f7358SJed Brown 
8910e6139122SMatthew G. Knepley /*@
89112827ebadSStefano Zampini   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8912e6139122SMatthew G. Knepley 
89132827ebadSStefano Zampini   Input Parameters:
89142827ebadSStefano Zampini + dm - The `DMPLEX` object
89152827ebadSStefano Zampini - ct - The `DMPolytopeType` of the cell
8916e6139122SMatthew G. Knepley 
8917e6139122SMatthew G. Knepley   Output Parameters:
89182827ebadSStefano Zampini + start - The first cell of this type, or `NULL`
89192827ebadSStefano Zampini - end   - The upper bound on this celltype, or `NULL`
8920e6139122SMatthew G. Knepley 
89212a9f31c0SMatthew G. Knepley   Level: advanced
8922e6139122SMatthew G. Knepley 
89232827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8924e6139122SMatthew G. Knepley @*/
8925ce78bad3SBarry Smith PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end)
8926d71ae5a4SJacob Faibussowitsch {
89272827ebadSStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
89282827ebadSStefano Zampini   DMLabel  label;
89292827ebadSStefano Zampini   PetscInt pStart, pEnd;
8930e6139122SMatthew G. Knepley 
8931e6139122SMatthew G. Knepley   PetscFunctionBegin;
8932e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89332827ebadSStefano Zampini   if (start) {
89344f572ea9SToby Isaac     PetscAssertPointer(start, 3);
89352827ebadSStefano Zampini     *start = 0;
89362827ebadSStefano Zampini   }
89372827ebadSStefano Zampini   if (end) {
89384f572ea9SToby Isaac     PetscAssertPointer(end, 4);
89392827ebadSStefano Zampini     *end = 0;
89402827ebadSStefano Zampini   }
89412827ebadSStefano Zampini   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
89422827ebadSStefano Zampini   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
89432827ebadSStefano Zampini   if (mesh->tr) {
89442827ebadSStefano Zampini     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
89452827ebadSStefano Zampini   } else {
89462827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
89472827ebadSStefano Zampini     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
89482827ebadSStefano Zampini     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
89492827ebadSStefano Zampini   }
89503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8951e6139122SMatthew G. Knepley }
8952e6139122SMatthew G. Knepley 
895321c42226SMatthew G. Knepley /*@
895421c42226SMatthew G. Knepley   DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum
895521c42226SMatthew G. Knepley 
895621c42226SMatthew G. Knepley   Input Parameters:
895721c42226SMatthew G. Knepley + dm    - The `DMPLEX` object
895821c42226SMatthew G. Knepley - depth - The depth for the given point stratum
895921c42226SMatthew G. Knepley 
896021c42226SMatthew G. Knepley   Output Parameter:
896121c42226SMatthew G. Knepley . gsize - The global number of points in the stratum
896221c42226SMatthew G. Knepley 
896321c42226SMatthew G. Knepley   Level: advanced
896421c42226SMatthew G. Knepley 
896521c42226SMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
896621c42226SMatthew G. Knepley @*/
896721c42226SMatthew G. Knepley PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize)
896821c42226SMatthew G. Knepley {
896921c42226SMatthew G. Knepley   PetscSF         sf;
897021c42226SMatthew G. Knepley   const PetscInt *leaves;
897121c42226SMatthew G. Knepley   PetscInt        Nl, loc, start, end, lsize = 0;
897221c42226SMatthew G. Knepley 
897321c42226SMatthew G. Knepley   PetscFunctionBegin;
897421c42226SMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
897521c42226SMatthew G. Knepley   PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
897621c42226SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end));
897721c42226SMatthew G. Knepley   for (PetscInt p = start; p < end; ++p) {
897821c42226SMatthew G. Knepley     PetscCall(PetscFindInt(p, Nl, leaves, &loc));
897921c42226SMatthew G. Knepley     if (loc < 0) ++lsize;
898021c42226SMatthew G. Knepley   }
8981458b0db5SMartin Diehl   PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
898221c42226SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
898321c42226SMatthew G. Knepley }
898421c42226SMatthew G. Knepley 
8985d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8986d71ae5a4SJacob Faibussowitsch {
8987552f7358SJed Brown   PetscSection section, globalSection;
8988552f7358SJed Brown   PetscInt    *numbers, p;
8989552f7358SJed Brown 
8990552f7358SJed Brown   PetscFunctionBegin;
8991d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
89929566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
89939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
899448a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
89959566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8996eb9d3e4dSMatthew G. Knepley   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection));
89979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8998552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
89999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
9000ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
9001ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
9002552f7358SJed Brown   }
90039566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
9004ef48cebcSMatthew G. Knepley   if (globalSize) {
9005ef48cebcSMatthew G. Knepley     PetscLayout layout;
90069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
90079566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
90089566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
9009ef48cebcSMatthew G. Knepley   }
90109566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
90119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
90123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9013552f7358SJed Brown }
9014552f7358SJed Brown 
9015e2b8d0fcSMatthew G. Knepley /*@
9016e2b8d0fcSMatthew G. Knepley   DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process
9017e2b8d0fcSMatthew G. Knepley 
9018bc9da2b0SJose E. Roman   Input Parameters:
9019e2b8d0fcSMatthew G. Knepley + dm         - The `DMPLEX` object
9020e2b8d0fcSMatthew G. Knepley - includeAll - Whether to include all cells, or just the simplex and box cells
9021e2b8d0fcSMatthew G. Knepley 
9022e2b8d0fcSMatthew G. Knepley   Output Parameter:
9023e2b8d0fcSMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
9024e2b8d0fcSMatthew G. Knepley 
9025e2b8d0fcSMatthew G. Knepley   Level: developer
9026e2b8d0fcSMatthew G. Knepley 
9027e2b8d0fcSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`
9028e2b8d0fcSMatthew G. Knepley @*/
9029e2b8d0fcSMatthew G. Knepley PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers)
9030d71ae5a4SJacob Faibussowitsch {
9031412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
9032552f7358SJed Brown 
9033552f7358SJed Brown   PetscFunctionBegin;
90349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
9035e2b8d0fcSMatthew G. Knepley   if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
90369566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
90379566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
90383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9039552f7358SJed Brown }
904081ed3555SMatthew G. Knepley 
90418dab3259SMatthew G. Knepley /*@
90427cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
90437cd05799SMatthew G. Knepley 
90447cd05799SMatthew G. Knepley   Input Parameter:
9045a1cb98faSBarry Smith . dm - The `DMPLEX` object
90467cd05799SMatthew G. Knepley 
90477cd05799SMatthew G. Knepley   Output Parameter:
90487cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
90497cd05799SMatthew G. Knepley 
90507cd05799SMatthew G. Knepley   Level: developer
90517cd05799SMatthew G. Knepley 
9052e2b8d0fcSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()`
90537cd05799SMatthew G. Knepley @*/
9054d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9055d71ae5a4SJacob Faibussowitsch {
905681ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
905781ed3555SMatthew G. Knepley 
905881ed3555SMatthew G. Knepley   PetscFunctionBegin;
905981ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9060e2b8d0fcSMatthew G. Knepley   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers));
9061552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
90623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9063552f7358SJed Brown }
9064552f7358SJed Brown 
9065d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
9066d71ae5a4SJacob Faibussowitsch {
9067412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
906881ed3555SMatthew G. Knepley 
906981ed3555SMatthew G. Knepley   PetscFunctionBegin;
907081ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
90729566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
90733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
907481ed3555SMatthew G. Knepley }
907581ed3555SMatthew G. Knepley 
90768dab3259SMatthew G. Knepley /*@
90776aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
90787cd05799SMatthew G. Knepley 
90797cd05799SMatthew G. Knepley   Input Parameter:
9080a1cb98faSBarry Smith . dm - The `DMPLEX` object
90817cd05799SMatthew G. Knepley 
90827cd05799SMatthew G. Knepley   Output Parameter:
90837cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
90847cd05799SMatthew G. Knepley 
90857cd05799SMatthew G. Knepley   Level: developer
90867cd05799SMatthew G. Knepley 
90871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
90887cd05799SMatthew G. Knepley @*/
9089d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9090d71ae5a4SJacob Faibussowitsch {
9091552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
9092552f7358SJed Brown 
9093552f7358SJed Brown   PetscFunctionBegin;
9094552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90959566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
9096552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
90973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9098552f7358SJed Brown }
9099552f7358SJed Brown 
91008dab3259SMatthew G. Knepley /*@
9101966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
9102966484cfSJed Brown 
910320f4b53cSBarry Smith   Collective
91047cd05799SMatthew G. Knepley 
91057cd05799SMatthew G. Knepley   Input Parameter:
9106a1cb98faSBarry Smith . dm - The `DMPLEX` object
91077cd05799SMatthew G. Knepley 
91087cd05799SMatthew G. Knepley   Output Parameter:
91097cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
91107cd05799SMatthew G. Knepley 
9111a1cb98faSBarry Smith   Level: developer
9112966484cfSJed Brown 
9113a1cb98faSBarry Smith   Notes:
9114a1cb98faSBarry Smith   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
9115966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
9116966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
9117966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
9118966484cfSJed Brown 
9119966484cfSJed Brown   The partitioned mesh is
9120966484cfSJed Brown   ```
9121966484cfSJed Brown   (2)--0--(3)--1--(4)    (1)--0--(2)
9122966484cfSJed Brown   ```
9123966484cfSJed Brown   and its global numbering is
9124966484cfSJed Brown   ```
9125966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
9126966484cfSJed Brown   ```
9127966484cfSJed Brown   Then the global numbering is provided as
9128966484cfSJed Brown   ```
9129966484cfSJed Brown   [0] Number of indices in set 5
9130966484cfSJed Brown   [0] 0 0
9131966484cfSJed Brown   [0] 1 1
9132966484cfSJed Brown   [0] 2 3
9133966484cfSJed Brown   [0] 3 4
9134966484cfSJed Brown   [0] 4 -6
9135966484cfSJed Brown   [1] Number of indices in set 3
9136966484cfSJed Brown   [1] 0 2
9137966484cfSJed Brown   [1] 1 5
9138966484cfSJed Brown   [1] 2 6
9139966484cfSJed Brown   ```
9140966484cfSJed Brown 
91411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
91427cd05799SMatthew G. Knepley @*/
9143d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
9144d71ae5a4SJacob Faibussowitsch {
9145ef48cebcSMatthew G. Knepley   IS        nums[4];
9146862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
9147ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
91480c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
9149ef48cebcSMatthew G. Knepley 
9150ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
9151ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
91530c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
91549566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
91550c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
9156862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
9157862913ffSStefano Zampini     PetscInt end;
9158862913ffSStefano Zampini 
9159862913ffSStefano Zampini     depths[d] = depth - d;
91609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
91610c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
9162862913ffSStefano Zampini   }
91630c15888dSMatthew G. Knepley   if (empty)
91640c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
91650c15888dSMatthew G. Knepley       depths[d] = -1;
91660c15888dSMatthew G. Knepley       starts[d] = -1;
91670c15888dSMatthew G. Knepley     }
91680c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
9169e91c04dfSPierre Jolivet   PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
9170ad540459SPierre 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]);
91710c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
9172ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
9173ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
9174ef48cebcSMatthew G. Knepley 
91759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
91769566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
9177ef48cebcSMatthew G. Knepley     shift += gsize;
9178ef48cebcSMatthew G. Knepley   }
9179d1c35871SJed Brown   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
91809566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
91813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9182ef48cebcSMatthew G. Knepley }
9183ef48cebcSMatthew G. Knepley 
918408a22f4bSMatthew G. Knepley /*@
9185484edb7dSMatthew G. Knepley   DMPlexCreateEdgeNumbering - Create a global numbering for edges.
9186484edb7dSMatthew G. Knepley 
9187484edb7dSMatthew G. Knepley   Collective
9188484edb7dSMatthew G. Knepley 
9189484edb7dSMatthew G. Knepley   Input Parameter:
9190484edb7dSMatthew G. Knepley . dm - The `DMPLEX` object
9191484edb7dSMatthew G. Knepley 
9192484edb7dSMatthew G. Knepley   Output Parameter:
9193484edb7dSMatthew G. Knepley . globalEdgeNumbers - Global numbers for all edges on this process
9194484edb7dSMatthew G. Knepley 
9195484edb7dSMatthew G. Knepley   Level: developer
9196484edb7dSMatthew G. Knepley 
9197484edb7dSMatthew G. Knepley   Notes:
9198484edb7dSMatthew 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).
9199484edb7dSMatthew G. Knepley 
9200484edb7dSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()`
9201484edb7dSMatthew G. Knepley @*/
9202484edb7dSMatthew G. Knepley PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers)
9203484edb7dSMatthew G. Knepley {
9204484edb7dSMatthew G. Knepley   PetscSF  sf;
9205484edb7dSMatthew G. Knepley   PetscInt eStart, eEnd;
9206484edb7dSMatthew G. Knepley 
9207484edb7dSMatthew G. Knepley   PetscFunctionBegin;
9208484edb7dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9209484edb7dSMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
9210484edb7dSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9211484edb7dSMatthew G. Knepley   PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers));
9212484edb7dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9213484edb7dSMatthew G. Knepley }
9214484edb7dSMatthew G. Knepley 
9215484edb7dSMatthew G. Knepley /*@
921608a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
921708a22f4bSMatthew G. Knepley 
921808a22f4bSMatthew G. Knepley   Input Parameter:
9219a1cb98faSBarry Smith . dm - The `DMPLEX` object
922008a22f4bSMatthew G. Knepley 
922108a22f4bSMatthew G. Knepley   Output Parameter:
922208a22f4bSMatthew G. Knepley . ranks - The rank field
922308a22f4bSMatthew G. Knepley 
9224a1cb98faSBarry Smith   Options Database Key:
922520f4b53cSBarry Smith . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
922608a22f4bSMatthew G. Knepley 
922708a22f4bSMatthew G. Knepley   Level: intermediate
922808a22f4bSMatthew G. Knepley 
92291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
923008a22f4bSMatthew G. Knepley @*/
9231d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
9232d71ae5a4SJacob Faibussowitsch {
923308a22f4bSMatthew G. Knepley   DM             rdm;
923408a22f4bSMatthew G. Knepley   PetscFE        fe;
923508a22f4bSMatthew G. Knepley   PetscScalar   *r;
923608a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
9237a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
923808a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
9239a55f9a55SMatthew G. Knepley   PetscBool      simplex;
924008a22f4bSMatthew G. Knepley 
924108a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
9242f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
92434f572ea9SToby Isaac   PetscAssertPointer(ranks, 2);
92449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
92459566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
92469566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
92479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
92489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9249a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
92509566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
92519566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
92529566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
92539566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
92549566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
92559566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
92569566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
92579566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
925808a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
925908a22f4bSMatthew G. Knepley     PetscScalar *lr;
926008a22f4bSMatthew G. Knepley 
92619566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
926271f09efeSPierre Jolivet     if (lr) *lr = rank;
926308a22f4bSMatthew G. Knepley   }
92649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
92659566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
92663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
926708a22f4bSMatthew G. Knepley }
926808a22f4bSMatthew G. Knepley 
9269ca8062c8SMatthew G. Knepley /*@
9270acf3173eSStefano Zampini   DMPlexCreateLabelField - Create a field whose value is the label value for that point
927118e14f0cSMatthew G. Knepley 
927218e14f0cSMatthew G. Knepley   Input Parameters:
927320f4b53cSBarry Smith + dm    - The `DMPLEX`
927420f4b53cSBarry Smith - label - The `DMLabel`
927518e14f0cSMatthew G. Knepley 
927618e14f0cSMatthew G. Knepley   Output Parameter:
927718e14f0cSMatthew G. Knepley . val - The label value field
927818e14f0cSMatthew G. Knepley 
927920f4b53cSBarry Smith   Options Database Key:
928020f4b53cSBarry Smith . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
928118e14f0cSMatthew G. Knepley 
928218e14f0cSMatthew G. Knepley   Level: intermediate
928318e14f0cSMatthew G. Knepley 
92841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
928518e14f0cSMatthew G. Knepley @*/
9286d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
9287d71ae5a4SJacob Faibussowitsch {
92881033741fSStefano Zampini   DM             rdm, plex;
9289acf3173eSStefano Zampini   Vec            lval;
9290acf3173eSStefano Zampini   PetscSection   section;
929118e14f0cSMatthew G. Knepley   PetscFE        fe;
929218e14f0cSMatthew G. Knepley   PetscScalar   *v;
9293acf3173eSStefano Zampini   PetscInt       dim, pStart, pEnd, p, cStart;
9294acf3173eSStefano Zampini   DMPolytopeType ct;
9295acf3173eSStefano Zampini   char           name[PETSC_MAX_PATH_LEN];
9296acf3173eSStefano Zampini   const char    *lname, *prefix;
929718e14f0cSMatthew G. Knepley 
929818e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
929918e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93004f572ea9SToby Isaac   PetscAssertPointer(label, 2);
93014f572ea9SToby Isaac   PetscAssertPointer(val, 3);
93029566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
9303acf3173eSStefano Zampini   PetscCall(DMConvert(rdm, DMPLEX, &plex));
9304acf3173eSStefano Zampini   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL));
9305acf3173eSStefano Zampini   PetscCall(DMPlexGetCellType(plex, cStart, &ct));
9306acf3173eSStefano Zampini   PetscCall(DMDestroy(&plex));
93079566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
9308acf3173eSStefano Zampini   PetscCall(DMGetOptionsPrefix(dm, &prefix));
9309acf3173eSStefano Zampini   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
9310acf3173eSStefano Zampini   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname));
9311acf3173eSStefano Zampini   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe));
9312acf3173eSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)fe, ""));
93139566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
93149566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
93159566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
93169566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
9317acf3173eSStefano Zampini   PetscCall(DMCreateLocalVector(rdm, &lval));
9318acf3173eSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)*val, lname));
9319acf3173eSStefano Zampini   PetscCall(DMGetLocalSection(rdm, &section));
9320acf3173eSStefano Zampini   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
9321acf3173eSStefano Zampini   PetscCall(VecGetArray(lval, &v));
9322acf3173eSStefano Zampini   for (p = pStart; p < pEnd; ++p) {
9323acf3173eSStefano Zampini     PetscInt cval, dof, off;
932418e14f0cSMatthew G. Knepley 
9325acf3173eSStefano Zampini     PetscCall(PetscSectionGetDof(section, p, &dof));
9326acf3173eSStefano Zampini     if (!dof) continue;
9327acf3173eSStefano Zampini     PetscCall(DMLabelGetValue(label, p, &cval));
9328acf3173eSStefano Zampini     PetscCall(PetscSectionGetOffset(section, p, &off));
9329acf3173eSStefano Zampini     for (PetscInt d = 0; d < dof; d++) v[off + d] = cval;
933018e14f0cSMatthew G. Knepley   }
9331acf3173eSStefano Zampini   PetscCall(VecRestoreArray(lval, &v));
9332acf3173eSStefano Zampini   PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val));
9333acf3173eSStefano Zampini   PetscCall(VecDestroy(&lval));
93349566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
93353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933618e14f0cSMatthew G. Knepley }
933718e14f0cSMatthew G. Knepley 
933818e14f0cSMatthew G. Knepley /*@
9339ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
9340ca8062c8SMatthew G. Knepley 
934169916449SMatthew G. Knepley   Input Parameter:
9342a1cb98faSBarry Smith . dm - The `DMPLEX` object
9343a1cb98faSBarry Smith 
9344a1cb98faSBarry Smith   Level: developer
9345ca8062c8SMatthew G. Knepley 
934695eb5ee5SVaclav Hapla   Notes:
934795eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
934895eb5ee5SVaclav Hapla 
934920f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9350ca8062c8SMatthew G. Knepley 
93511cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9352ca8062c8SMatthew G. Knepley @*/
9353d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
9354d71ae5a4SJacob Faibussowitsch {
9355ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
9356ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
9357ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
935857beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
935957beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
9360ca8062c8SMatthew G. Knepley 
9361ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9362ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93639566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
93649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
93659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
9366ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
93679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9368ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
93699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
93709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
9371ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
937242e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
937342e66dfaSMatthew G. Knepley       PetscInt  d;
937442e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
93759371c9d4SSatish Balay         if (cone[c] == cone[d]) {
93769371c9d4SSatish Balay           dup = PETSC_TRUE;
93779371c9d4SSatish Balay           break;
93789371c9d4SSatish Balay         }
937942e66dfaSMatthew G. Knepley       }
93809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
93819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
9382ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
9383ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
9384ca8062c8SMatthew G. Knepley       }
938542e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
938663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
938748a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
93889566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
938963a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
939048a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
93919566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
939263a3b9bcSJacob 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]);
9393f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
9394ca8062c8SMatthew G. Knepley       }
939542e66dfaSMatthew G. Knepley     }
93969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
93979371c9d4SSatish Balay     if (p != pp) {
93989371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
93999371c9d4SSatish Balay       continue;
94009371c9d4SSatish Balay     }
94019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
94029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
9403ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
94049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
94059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
9406ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
94079566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
94089371c9d4SSatish Balay         if (cone[c] != pp) {
94099371c9d4SSatish Balay           c = 0;
94109371c9d4SSatish Balay           break;
94119371c9d4SSatish Balay         }
9412ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
9413ca8062c8SMatthew G. Knepley       }
9414ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
941563a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
941648a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
94179566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
941863a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
941948a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
94209566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
942163a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
9422ca8062c8SMatthew G. Knepley       }
9423ca8062c8SMatthew G. Knepley     }
9424ca8062c8SMatthew G. Knepley   }
942557beb4faSStefano Zampini   if (storagecheck) {
94269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
94279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
942863a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
942957beb4faSStefano Zampini   }
94303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9431ca8062c8SMatthew G. Knepley }
9432ca8062c8SMatthew G. Knepley 
9433412e9a14SMatthew G. Knepley /*
9434412e9a14SMatthew 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.
9435412e9a14SMatthew G. Knepley */
9436d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
9437d71ae5a4SJacob Faibussowitsch {
9438412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
9439412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
9440412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
9441412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
9442412e9a14SMatthew G. Knepley 
9443412e9a14SMatthew G. Knepley   PetscFunctionBegin;
9444412e9a14SMatthew G. Knepley   *unsplit = 0;
9445412e9a14SMatthew G. Knepley   switch (ct) {
9446d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
9447d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
9448d71ae5a4SJacob Faibussowitsch     break;
9449412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
94509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
94519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9452412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
94539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
9454412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
9455412e9a14SMatthew G. Knepley     }
9456412e9a14SMatthew G. Knepley     break;
9457412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
9458412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
94599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
94609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9461412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
94629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
94639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
9464412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
94659566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
9466412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
9467412e9a14SMatthew G. Knepley           PetscInt p;
94689371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
94699371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
9470412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
9471412e9a14SMatthew G. Knepley         }
9472412e9a14SMatthew G. Knepley       }
9473412e9a14SMatthew G. Knepley     }
9474412e9a14SMatthew G. Knepley     break;
9475d71ae5a4SJacob Faibussowitsch   default:
9476d71ae5a4SJacob Faibussowitsch     break;
9477412e9a14SMatthew G. Knepley   }
9478412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
94799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
9480412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
9481412e9a14SMatthew G. Knepley   }
94823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9483412e9a14SMatthew G. Knepley }
9484412e9a14SMatthew G. Knepley 
9485ca8062c8SMatthew G. Knepley /*@
9486ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
9487ca8062c8SMatthew G. Knepley 
9488ca8062c8SMatthew G. Knepley   Input Parameters:
9489a1cb98faSBarry Smith + dm         - The `DMPLEX` object
949058723a97SMatthew G. Knepley - cellHeight - Normally 0
9491ca8062c8SMatthew G. Knepley 
9492a1cb98faSBarry Smith   Level: developer
9493a1cb98faSBarry Smith 
949495eb5ee5SVaclav Hapla   Notes:
949595eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
949625c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
9497ca8062c8SMatthew G. Knepley 
949820f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
949995eb5ee5SVaclav Hapla 
95001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9501ca8062c8SMatthew G. Knepley @*/
9502d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
9503d71ae5a4SJacob Faibussowitsch {
9504412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
9505412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
9506412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
9507ca8062c8SMatthew G. Knepley 
9508ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9509ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95109566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
95119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
95129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9513412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9514412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
9515412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
951658723a97SMatthew G. Knepley 
95179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9518412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
9519412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
95209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
952163a3b9bcSJacob 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));
9522412e9a14SMatthew G. Knepley     }
95239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
952458723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
952558723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
9526412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
952758723a97SMatthew G. Knepley     }
95289566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9529412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
9530412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
9531412e9a14SMatthew G. Knepley       PetscInt unsplit;
953242363296SMatthew G. Knepley 
95339566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9534412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
953542363296SMatthew G. Knepley     }
953663a3b9bcSJacob 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));
953742363296SMatthew G. Knepley   }
95383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9539ca8062c8SMatthew G. Knepley }
95409bf0dad6SMatthew G. Knepley 
95419bf0dad6SMatthew G. Knepley /*@
95429bf0dad6SMatthew 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
95439bf0dad6SMatthew G. Knepley 
954420f4b53cSBarry Smith   Collective
9545899ea2b8SJacob Faibussowitsch 
95469bf0dad6SMatthew G. Knepley   Input Parameters:
9547a1cb98faSBarry Smith + dm         - The `DMPLEX` object
95489bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
95499bf0dad6SMatthew G. Knepley 
9550a1cb98faSBarry Smith   Level: developer
9551a1cb98faSBarry Smith 
955245da879fSVaclav Hapla   Notes:
955345da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
955445da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
955545da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
955645da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
95579bf0dad6SMatthew G. Knepley 
9558a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
955995eb5ee5SVaclav Hapla 
95601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
95619bf0dad6SMatthew G. Knepley @*/
9562d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
9563d71ae5a4SJacob Faibussowitsch {
9564ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
9565899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
95669bf0dad6SMatthew G. Knepley 
95679bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
95689bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95698f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
95703ba16761SJacob Faibussowitsch   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
95718f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
95723ba16761SJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
95733ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
9574899ea2b8SJacob Faibussowitsch   }
9575899ea2b8SJacob Faibussowitsch 
95769566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
95779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
95789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9579ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
95809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
95813554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
9582412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
9583412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
9584ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
9585412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
9586412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
95879bf0dad6SMatthew G. Knepley 
95889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
95899566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9590412e9a14SMatthew G. Knepley       if (unsplit) continue;
95919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
95929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
95939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
95949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
95959bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
95969bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
95979bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
95989bf0dad6SMatthew G. Knepley       }
95999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
960063a3b9bcSJacob 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);
96019bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
9602d4961f80SStefano Zampini         DMPolytopeType fct;
96039bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
96049bf0dad6SMatthew G. Knepley 
96059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
96069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
96079bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
96089bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
96099bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
96109bf0dad6SMatthew G. Knepley         }
961163a3b9bcSJacob 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]);
96129bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
9613b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
9614b5a892a1SMatthew G. Knepley             PetscInt v1;
9615b5a892a1SMatthew G. Knepley 
96169566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
961763a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
96189566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
961963a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
96209566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
962163a3b9bcSJacob 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]);
9622b5a892a1SMatthew G. Knepley           }
96239bf0dad6SMatthew G. Knepley         }
96249566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
9625412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
96269bf0dad6SMatthew G. Knepley       }
96279566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
96289566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
96299bf0dad6SMatthew G. Knepley     }
96303554e41dSMatthew G. Knepley   }
96313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9632552f7358SJed Brown }
96333913d7c8SMatthew G. Knepley 
9634bb6a34a8SMatthew G. Knepley /*@
9635bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
9636bb6a34a8SMatthew G. Knepley 
9637bb6a34a8SMatthew G. Knepley   Input Parameter:
9638a1cb98faSBarry Smith . dm - The `DMPLEX` object
9639a1cb98faSBarry Smith 
9640a1cb98faSBarry Smith   Level: developer
9641bb6a34a8SMatthew G. Knepley 
964295eb5ee5SVaclav Hapla   Notes:
964395eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
964495eb5ee5SVaclav Hapla 
964520f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9646bb6a34a8SMatthew G. Knepley 
96471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9648bb6a34a8SMatthew G. Knepley @*/
9649d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
9650d71ae5a4SJacob Faibussowitsch {
9651a2a9e04cSMatthew G. Knepley   Vec       coordinates;
9652bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
9653bb6a34a8SMatthew G. Knepley   PetscReal vol;
965451a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9655bb6a34a8SMatthew G. Knepley 
9656bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
96579566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
96589566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
96593ba16761SJacob Faibussowitsch   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
96609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
9661bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
96629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9663a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
96649566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
96653ba16761SJacob Faibussowitsch   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9666412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9667412e9a14SMatthew G. Knepley     DMPolytopeType ct;
9668412e9a14SMatthew G. Knepley     PetscInt       unsplit;
9669412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
9670412e9a14SMatthew G. Knepley 
96719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9672412e9a14SMatthew G. Knepley     switch (ct) {
9673412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9674412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9675d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9676d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
9677d71ae5a4SJacob Faibussowitsch       break;
9678d71ae5a4SJacob Faibussowitsch     default:
9679d71ae5a4SJacob Faibussowitsch       break;
9680412e9a14SMatthew G. Knepley     }
9681412e9a14SMatthew G. Knepley     switch (ct) {
9682412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
9683412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9684412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9685d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
9686d71ae5a4SJacob Faibussowitsch       continue;
9687d71ae5a4SJacob Faibussowitsch     default:
9688d71ae5a4SJacob Faibussowitsch       break;
9689412e9a14SMatthew G. Knepley     }
96909566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9691412e9a14SMatthew G. Knepley     if (unsplit) continue;
96929566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
96931dca8a05SBarry 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);
969463a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
96956858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
96966858538eSMatthew G. Knepley     if (depth > 1) {
96979566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
96981dca8a05SBarry 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);
969963a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9700bb6a34a8SMatthew G. Knepley     }
9701bb6a34a8SMatthew G. Knepley   }
97023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9703bb6a34a8SMatthew G. Knepley }
9704bb6a34a8SMatthew G. Knepley 
970503da9461SVaclav Hapla /*@
970620f4b53cSBarry Smith   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
97077726db96SVaclav Hapla 
970820f4b53cSBarry Smith   Collective
970903da9461SVaclav Hapla 
971003da9461SVaclav Hapla   Input Parameters:
9711a1cb98faSBarry Smith + dm              - The `DMPLEX` object
971220f4b53cSBarry Smith . pointSF         - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9713a1cb98faSBarry Smith - allowExtraRoots - Flag to allow extra points not present in the `DM`
9714a1cb98faSBarry Smith 
9715a1cb98faSBarry Smith   Level: developer
971603da9461SVaclav Hapla 
9717e83a0d2dSVaclav Hapla   Notes:
9718e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
971903da9461SVaclav Hapla 
9720a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
972195eb5ee5SVaclav Hapla 
9722baca6076SPierre Jolivet   Extra roots can come from periodic cuts, where additional points appear on the boundary
9723d7d32a9aSMatthew G. Knepley 
97241cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
972503da9461SVaclav Hapla @*/
9726d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9727d71ae5a4SJacob Faibussowitsch {
97287726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
97297726db96SVaclav Hapla   const PetscInt    *locals;
97307726db96SVaclav Hapla   const PetscSFNode *remotes;
9731f0cfc026SVaclav Hapla   PetscBool          distributed;
97327726db96SVaclav Hapla   MPI_Comm           comm;
97337726db96SVaclav Hapla   PetscMPIInt        rank;
973403da9461SVaclav Hapla 
973503da9461SVaclav Hapla   PetscFunctionBegin;
973603da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
97377726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
97387726db96SVaclav Hapla   else pointSF = dm->sf;
97397726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
97407726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
97417726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
97427726db96SVaclav Hapla   {
97437726db96SVaclav Hapla     PetscMPIInt mpiFlag;
97447726db96SVaclav Hapla 
97457726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
97467726db96SVaclav 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);
97477726db96SVaclav Hapla   }
97487726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
97499566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
97507726db96SVaclav Hapla   if (!distributed) {
97517726db96SVaclav 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);
97523ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
97538918e3e2SVaclav Hapla   }
97547726db96SVaclav 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);
97557726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
975603da9461SVaclav Hapla 
97577726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
97587726db96SVaclav Hapla   {
97597726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
97607726db96SVaclav Hapla 
97617726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
97627726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9763d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
97647726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
97657726db96SVaclav Hapla   }
97667726db96SVaclav Hapla 
97677726db96SVaclav Hapla   /* Check there are no cells in interface */
97687726db96SVaclav Hapla   if (!overlap) {
97697726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
97707726db96SVaclav Hapla 
97719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
97729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9773f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
97747726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
9775f5869d18SMatthew G. Knepley 
97767726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
97777726db96SVaclav Hapla     }
977803da9461SVaclav Hapla   }
9779ece87651SVaclav Hapla 
97807726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
97817726db96SVaclav Hapla   {
97827726db96SVaclav Hapla     const PetscInt *rootdegree;
97837726db96SVaclav Hapla 
97847726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
97857726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9786f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
97877726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9788f5869d18SMatthew G. Knepley       const PetscInt *cone;
9789f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9790f5869d18SMatthew G. Knepley 
97919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
97929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9793f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9794f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
97957726db96SVaclav Hapla           if (locals) {
97969566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
97977726db96SVaclav Hapla           } else {
97987726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
97997726db96SVaclav Hapla           }
980063a3b9bcSJacob 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]);
9801f5869d18SMatthew G. Knepley         }
9802f5869d18SMatthew G. Knepley       }
9803ece87651SVaclav Hapla     }
98047726db96SVaclav Hapla   }
98053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
980603da9461SVaclav Hapla }
980703da9461SVaclav Hapla 
98087f9d8d6cSVaclav Hapla /*@
9809217fe35eSMatthew G. Knepley   DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices.
9810217fe35eSMatthew G. Knepley 
9811217fe35eSMatthew G. Knepley   Collective
9812217fe35eSMatthew G. Knepley 
9813217fe35eSMatthew G. Knepley   Input Parameter:
9814217fe35eSMatthew G. Knepley . dm - The `DMPLEX` object
9815217fe35eSMatthew G. Knepley 
9816217fe35eSMatthew G. Knepley   Level: developer
9817217fe35eSMatthew G. Knepley 
9818217fe35eSMatthew G. Knepley   Notes:
9819217fe35eSMatthew G. Knepley   This is mainly intended for debugging/testing purposes.
9820217fe35eSMatthew G. Knepley 
9821217fe35eSMatthew G. Knepley   Other cell types which are disconnected would be caught by the symmetry and face checks.
9822217fe35eSMatthew G. Knepley 
9823217fe35eSMatthew G. Knepley   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9824217fe35eSMatthew G. Knepley 
9825217fe35eSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()`
9826217fe35eSMatthew G. Knepley @*/
9827217fe35eSMatthew G. Knepley PetscErrorCode DMPlexCheckOrphanVertices(DM dm)
9828217fe35eSMatthew G. Knepley {
9829217fe35eSMatthew G. Knepley   PetscInt pStart, pEnd, vStart, vEnd;
9830217fe35eSMatthew G. Knepley 
9831217fe35eSMatthew G. Knepley   PetscFunctionBegin;
9832217fe35eSMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9833217fe35eSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9834217fe35eSMatthew G. Knepley   if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS);
9835217fe35eSMatthew G. Knepley   for (PetscInt v = vStart; v < vEnd; ++v) {
9836217fe35eSMatthew G. Knepley     PetscInt suppSize;
9837217fe35eSMatthew G. Knepley 
9838217fe35eSMatthew G. Knepley     PetscCall(DMPlexGetSupportSize(dm, v, &suppSize));
9839217fe35eSMatthew G. Knepley     PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v);
9840217fe35eSMatthew G. Knepley   }
9841217fe35eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9842217fe35eSMatthew G. Knepley }
9843217fe35eSMatthew G. Knepley 
9844217fe35eSMatthew G. Knepley /*@
984520f4b53cSBarry Smith   DMPlexCheck - Perform various checks of `DMPLEX` sanity
98467f9d8d6cSVaclav Hapla 
98477f9d8d6cSVaclav Hapla   Input Parameter:
9848a1cb98faSBarry Smith . dm - The `DMPLEX` object
9849a1cb98faSBarry Smith 
9850a1cb98faSBarry Smith   Level: developer
98517f9d8d6cSVaclav Hapla 
98527f9d8d6cSVaclav Hapla   Notes:
98537f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
98547f9d8d6cSVaclav Hapla 
985520f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
98567f9d8d6cSVaclav Hapla 
985720f4b53cSBarry Smith   Currently does not include `DMPlexCheckCellShape()`.
98587f9d8d6cSVaclav Hapla 
98591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
98607f9d8d6cSVaclav Hapla @*/
9861d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9862d71ae5a4SJacob Faibussowitsch {
98637f9d8d6cSVaclav Hapla   PetscInt cellHeight;
98647f9d8d6cSVaclav Hapla 
9865b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
98667f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
98679566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
98689566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
98699566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
98709566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9871d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
98729566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
9873217fe35eSMatthew G. Knepley   PetscCall(DMPlexCheckOrphanVertices(dm));
98743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9875b5a892a1SMatthew G. Knepley }
9876b5a892a1SMatthew G. Knepley 
98779371c9d4SSatish Balay typedef struct cell_stats {
9878068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9879068a5610SStefano Zampini   PetscInt  count;
9880068a5610SStefano Zampini } cell_stats_t;
9881068a5610SStefano Zampini 
9882d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9883d71ae5a4SJacob Faibussowitsch {
9884068a5610SStefano Zampini   PetscInt i, N = *len;
9885068a5610SStefano Zampini 
9886068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9887068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9888068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9889068a5610SStefano Zampini 
9890068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9891068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9892068a5610SStefano Zampini     B->sum += A->sum;
9893068a5610SStefano Zampini     B->squaresum += A->squaresum;
9894068a5610SStefano Zampini     B->count += A->count;
9895068a5610SStefano Zampini   }
9896068a5610SStefano Zampini }
9897068a5610SStefano Zampini 
9898068a5610SStefano Zampini /*@
989943fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9900068a5610SStefano Zampini 
990120f4b53cSBarry Smith   Collective
99028261a58bSMatthew G. Knepley 
9903068a5610SStefano Zampini   Input Parameters:
9904a1cb98faSBarry Smith + dm        - The `DMPLEX` object
990520f4b53cSBarry Smith . output    - If true, statistics will be displayed on `stdout`
9906a1cb98faSBarry Smith - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9907a1cb98faSBarry Smith 
9908a1cb98faSBarry Smith   Level: developer
9909068a5610SStefano Zampini 
991095eb5ee5SVaclav Hapla   Notes:
991195eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
991295eb5ee5SVaclav Hapla 
9913a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9914068a5610SStefano Zampini 
99151cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9916068a5610SStefano Zampini @*/
9917d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9918d71ae5a4SJacob Faibussowitsch {
9919068a5610SStefano Zampini   DM           dmCoarse;
992043fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
992143fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
992243fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
992343fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9924412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
992543fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9926068a5610SStefano Zampini 
9927068a5610SStefano Zampini   PetscFunctionBegin;
9928068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9929068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9930068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9931068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9932068a5610SStefano Zampini   stats.count                 = 0;
9933068a5610SStefano Zampini 
99349566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
99359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
99369566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
99379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
99389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
99399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9940412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9941068a5610SStefano Zampini     PetscInt  i;
9942068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9943068a5610SStefano Zampini 
99449566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
994563a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
994643fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9947068a5610SStefano Zampini       frobJ += J[i] * J[i];
9948068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9949068a5610SStefano Zampini     }
9950068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9951068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9952068a5610SStefano Zampini 
9953068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9954068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9955068a5610SStefano Zampini     stats.sum += cond;
9956068a5610SStefano Zampini     stats.squaresum += cond2;
9957068a5610SStefano Zampini     stats.count++;
99588261a58bSMatthew G. Knepley     if (output && cond > limit) {
995943fa8764SMatthew G. Knepley       PetscSection coordSection;
996043fa8764SMatthew G. Knepley       Vec          coordsLocal;
996143fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
996243fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
996343fa8764SMatthew G. Knepley 
99649566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
99659566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
99669566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
996763a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
996843fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
996963a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
997043fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
99719566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
99729566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
997343fa8764SMatthew G. Knepley         }
99749566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
997543fa8764SMatthew G. Knepley       }
99769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
997743fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
997843fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
997943fa8764SMatthew G. Knepley 
998043fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
998143fa8764SMatthew G. Knepley           PetscReal len;
998243fa8764SMatthew G. Knepley 
99839566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
998463a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
998543fa8764SMatthew G. Knepley         }
998643fa8764SMatthew G. Knepley       }
99879566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
99889566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
998943fa8764SMatthew G. Knepley     }
9990068a5610SStefano Zampini   }
99919566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9992068a5610SStefano Zampini 
9993068a5610SStefano Zampini   if (size > 1) {
9994068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9995068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9996068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9997068a5610SStefano Zampini     MPI_Op       statReduce;
9998068a5610SStefano Zampini 
99999566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
100009566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
100019566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
100029566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
100039566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
100049566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
10005068a5610SStefano Zampini   } else {
100069566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
10007068a5610SStefano Zampini   }
10008dd400576SPatrick Sanan   if (rank == 0) {
10009068a5610SStefano Zampini     count = globalStats.count;
10010068a5610SStefano Zampini     min   = globalStats.min;
10011068a5610SStefano Zampini     max   = globalStats.max;
10012068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
10013068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
10014068a5610SStefano Zampini   }
10015068a5610SStefano Zampini 
1001648a46eb9SPierre 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));
100179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
10018068a5610SStefano Zampini 
100199566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
10020068a5610SStefano Zampini   if (dmCoarse) {
10021068a5610SStefano Zampini     PetscBool isplex;
10022068a5610SStefano Zampini 
100239566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
100241baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
10025068a5610SStefano Zampini   }
100263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10027068a5610SStefano Zampini }
10028068a5610SStefano Zampini 
10029f108dbd7SJacob Faibussowitsch /*@
10030f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
10031f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
10032f108dbd7SJacob Faibussowitsch 
1003320f4b53cSBarry Smith   Collective
10034f108dbd7SJacob Faibussowitsch 
10035f108dbd7SJacob Faibussowitsch   Input Parameters:
10036a1cb98faSBarry Smith + dm   - The `DMPLEX` object
10037a1cb98faSBarry Smith . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
10038f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
10039f108dbd7SJacob Faibussowitsch 
10040f108dbd7SJacob Faibussowitsch   Output Parameters:
1004120f4b53cSBarry Smith + OrthQual      - `Vec` containing orthogonal quality per cell
10042a1cb98faSBarry Smith - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
10043f108dbd7SJacob Faibussowitsch 
10044f108dbd7SJacob Faibussowitsch   Options Database Keys:
10045a1cb98faSBarry Smith + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
10046f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view   - view OrthQual vector.
10047f108dbd7SJacob Faibussowitsch 
10048a1cb98faSBarry Smith   Level: intermediate
10049a1cb98faSBarry Smith 
10050f108dbd7SJacob Faibussowitsch   Notes:
10051a4e35b19SJacob Faibussowitsch   Orthogonal quality is given by the following formula\:
10052f108dbd7SJacob Faibussowitsch 
10053a1cb98faSBarry Smith   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
10054f108dbd7SJacob Faibussowitsch 
10055f108dbd7SJacob 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
10056f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
10057f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
10058f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
10059f108dbd7SJacob Faibussowitsch 
10060f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
10061f108dbd7SJacob Faibussowitsch 
10062a1cb98faSBarry Smith   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
10063f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
10064f108dbd7SJacob Faibussowitsch 
10065f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
10066f108dbd7SJacob Faibussowitsch 
100671cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
10068f108dbd7SJacob Faibussowitsch @*/
10069ce78bad3SBarry Smith PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
10070d71ae5a4SJacob Faibussowitsch {
100716ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
100726ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
100736ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
10074f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
100756ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
10076f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
10077f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
10078f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
10079f108dbd7SJacob Faibussowitsch   IS                     glob;
10080f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
10081f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
10082f108dbd7SJacob Faibussowitsch 
10083f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
10084f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10085ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
100864f572ea9SToby Isaac   PetscAssertPointer(OrthQual, 4);
100876bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
100889566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
100899566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
1009063a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
100916ed19f2fSJacob Faibussowitsch   {
100926ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
100936ed19f2fSJacob Faibussowitsch 
100949566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
10095f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
10096f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
10097f108dbd7SJacob Faibussowitsch 
100989566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
1009998921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
10100f108dbd7SJacob Faibussowitsch     }
101016ed19f2fSJacob Faibussowitsch   }
10102f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
101034f572ea9SToby Isaac     PetscAssertPointer(OrthQualLabel, 5);
101049566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
101059566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
101069371c9d4SSatish Balay   } else {
101079371c9d4SSatish Balay     *OrthQualLabel = NULL;
101089371c9d4SSatish Balay   }
101099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
101109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
10111e2b8d0fcSMatthew G. Knepley   PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob));
101129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
101139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
101149566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
101159566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
101169566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
101179566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
101189566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
101199566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
101209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
101219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
101229566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
101239566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
101249566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
101259566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
101269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
101276ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
101286ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
10129f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
10130f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
10131898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
10132f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
10133f108dbd7SJacob Faibussowitsch 
101346ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
10135f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
10136f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
101379566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
101389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
10139f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
101409566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
101416ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
101426ed19f2fSJacob Faibussowitsch       PetscInt         i;
101436ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
10144f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
10145f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
10146f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
10147f108dbd7SJacob Faibussowitsch 
10148f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
10149f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
101509566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
10151f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
101526ed19f2fSJacob Faibussowitsch       {
101536ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
101546ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
101556ed19f2fSJacob Faibussowitsch 
101569566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
101579566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
101589566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
101596ed19f2fSJacob Faibussowitsch       }
10160f108dbd7SJacob Faibussowitsch 
10161f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
10162f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
10163f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
10164f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
10165f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
10166addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
10167addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
10168addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
10169f108dbd7SJacob Faibussowitsch       }
10170addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
10171addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
10172addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
10173f108dbd7SJacob Faibussowitsch 
10174f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
10175f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
10176f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
10177f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
10178f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
10179f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
10180f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
10181f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
10182f108dbd7SJacob Faibussowitsch       }
10183ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
10184ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
10185f108dbd7SJacob Faibussowitsch     }
101869566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
101879566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
10188f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
101896ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
10190f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
101919566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
10192f108dbd7SJacob Faibussowitsch     }
10193f108dbd7SJacob Faibussowitsch   }
101949566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
101959566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
101969566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
101979566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
101989566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
10199648c30bcSBarry Smith   PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
10200f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
102019566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
10202f108dbd7SJacob Faibussowitsch   }
102039566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
10204648c30bcSBarry Smith   PetscCall(PetscViewerDestroy(&vwr));
102059566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
102063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10207f108dbd7SJacob Faibussowitsch }
10208f108dbd7SJacob Faibussowitsch 
10209d5b43468SJose E. Roman /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
102101eb70e55SToby Isaac  * interpolator construction */
10211d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
10212d71ae5a4SJacob Faibussowitsch {
102131eb70e55SToby Isaac   PetscSection section, newSection, gsection;
102141eb70e55SToby Isaac   PetscSF      sf;
102151eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
102161eb70e55SToby Isaac 
102171eb70e55SToby Isaac   PetscFunctionBegin;
102181eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102194f572ea9SToby Isaac   PetscAssertPointer(odm, 2);
102209566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
102219566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
102225440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
102231eb70e55SToby Isaac   if (!ghasConstraints) {
102249566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
102251eb70e55SToby Isaac     *odm = dm;
102263ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
102271eb70e55SToby Isaac   }
102289566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
10229bb4b53efSMatthew G. Knepley   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm));
102309566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
102319566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
10232eb9d3e4dSMatthew G. Knepley   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection));
102339566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
102349566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
102353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102361eb70e55SToby Isaac }
102371eb70e55SToby Isaac 
10238d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
10239d71ae5a4SJacob Faibussowitsch {
102401eb70e55SToby Isaac   DM        dmco, dmfo;
102411eb70e55SToby Isaac   Mat       interpo;
102421eb70e55SToby Isaac   Vec       rscale;
102431eb70e55SToby Isaac   Vec       cglobalo, clocal;
102441eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
102451eb70e55SToby Isaac   PetscBool regular;
102461eb70e55SToby Isaac 
102471eb70e55SToby Isaac   PetscFunctionBegin;
102489566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
102499566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
102509566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
102519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
102529566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
102539566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
102549566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
102559566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
102569566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
102579566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
102589566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
102599566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
102609566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
102619566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
102629566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
102639566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
102649566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
102659566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
102669566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
102679566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
102689566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
102699566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
102709566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
102719566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
102721eb70e55SToby Isaac   *shift = fglobal;
102739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
102749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
102759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
102769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
102779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
102789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
102799566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
102809566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
102813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102821eb70e55SToby Isaac }
102831eb70e55SToby Isaac 
10284d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
10285d71ae5a4SJacob Faibussowitsch {
102861eb70e55SToby Isaac   PetscObject shifto;
102871eb70e55SToby Isaac   Vec         shift;
102881eb70e55SToby Isaac 
102891eb70e55SToby Isaac   PetscFunctionBegin;
102901eb70e55SToby Isaac   if (!interp) {
102911eb70e55SToby Isaac     Vec rscale;
102921eb70e55SToby Isaac 
102939566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
102949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
102951eb70e55SToby Isaac   } else {
102969566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
102971eb70e55SToby Isaac   }
102989566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
102991eb70e55SToby Isaac   if (!shifto) {
103009566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
103019566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
103021eb70e55SToby Isaac     shifto = (PetscObject)shift;
103039566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
103041eb70e55SToby Isaac   }
103051eb70e55SToby Isaac   shift = (Vec)shifto;
103069566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
103079566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
103089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
103093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103101eb70e55SToby Isaac }
103111eb70e55SToby Isaac 
10312bceba477SMatthew G. Knepley /* Pointwise interpolation
10313bceba477SMatthew G. Knepley      Just code FEM for now
10314bceba477SMatthew G. Knepley      u^f = I u^c
103154ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
103164ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
103174ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
10318bceba477SMatthew G. Knepley */
10319d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
10320d71ae5a4SJacob Faibussowitsch {
10321bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
10322bceba477SMatthew G. Knepley   PetscInt     m, n;
10323a063dac3SMatthew G. Knepley   void        *ctx;
1032468132eb9SMatthew G. Knepley   DM           cdm;
10325cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
10326bceba477SMatthew G. Knepley 
10327bceba477SMatthew G. Knepley   PetscFunctionBegin;
103289566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
103299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
103309566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
103319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
1033268132eb9SMatthew G. Knepley 
103339566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
103349566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
103359566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
103369566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
103379566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
1033868132eb9SMatthew G. Knepley 
103399566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
103409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
103419566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
103429566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
103439566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
103444db47ee9SStefano Zampini   if (scaling) {
103455d1c2e58SMatthew G. Knepley     /* Use naive scaling */
103469566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
103474db47ee9SStefano Zampini   }
103483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10349a063dac3SMatthew G. Knepley }
10350bceba477SMatthew G. Knepley 
10351d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
10352d71ae5a4SJacob Faibussowitsch {
103536dbf9973SLawrence Mitchell   VecScatter ctx;
1035490748bafSMatthew G. Knepley 
10355a063dac3SMatthew G. Knepley   PetscFunctionBegin;
103569566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
103579566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
103589566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
103593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10360bceba477SMatthew G. Knepley }
10361bceba477SMatthew G. Knepley 
10362d71ae5a4SJacob 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[])
10363d71ae5a4SJacob Faibussowitsch {
10364a102dd69SStefano Zampini   const PetscInt f  = (PetscInt)PetscRealPart(constants[numConstants]);
10365a102dd69SStefano Zampini   const PetscInt Nc = uOff[f + 1] - uOff[f];
10366a102dd69SStefano Zampini   for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
103673e9753d6SMatthew G. Knepley }
103683e9753d6SMatthew G. Knepley 
103691898fd5cSMatthew 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)
103701898fd5cSMatthew 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[])
103711898fd5cSMatthew G. Knepley {
103721898fd5cSMatthew G. Knepley   for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0;
103731898fd5cSMatthew G. Knepley }
103741898fd5cSMatthew G. Knepley 
103758e9849d2SStefano Zampini PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass)
10376d71ae5a4SJacob Faibussowitsch {
10377b4937a87SMatthew G. Knepley   DM           dmc;
10378b4937a87SMatthew G. Knepley   PetscDS      ds;
10379b4937a87SMatthew G. Knepley   Vec          ones, locmass;
10380b4937a87SMatthew G. Knepley   IS           cellIS;
10381b4937a87SMatthew G. Knepley   PetscFormKey key;
10382b4937a87SMatthew G. Knepley   PetscInt     depth;
10383b4937a87SMatthew G. Knepley 
10384b4937a87SMatthew G. Knepley   PetscFunctionBegin;
103859566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
103869566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
103879566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
10388a102dd69SStefano Zampini   for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
103898e9849d2SStefano Zampini   if (mass) PetscCall(DMCreateGlobalVector(dm, mass));
103908e9849d2SStefano Zampini   if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass));
103918e9849d2SStefano Zampini   else PetscCall(DMGetLocalVector(dm, &locmass));
103928e9849d2SStefano Zampini   PetscCall(DMGetLocalVector(dm, &ones));
103938e9849d2SStefano Zampini   PetscCall(DMPlexGetDepth(dm, &depth));
103948e9849d2SStefano Zampini   PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS));
103959566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
103969566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
10397b4937a87SMatthew G. Knepley   key.label = NULL;
10398b4937a87SMatthew G. Knepley   key.value = 0;
10399b4937a87SMatthew G. Knepley   key.field = 0;
10400b4937a87SMatthew G. Knepley   key.part  = 0;
10401754e4fbaSMatthew G. Knepley   PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
104029566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
104038e9849d2SStefano Zampini   if (mass) {
104048e9849d2SStefano Zampini     PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass));
104058e9849d2SStefano Zampini     PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass));
104068e9849d2SStefano Zampini   }
104078e9849d2SStefano Zampini   PetscCall(DMRestoreLocalVector(dm, &ones));
104088e9849d2SStefano Zampini   if (lmass) *lmass = locmass;
104098e9849d2SStefano Zampini   else PetscCall(DMRestoreLocalVector(dm, &locmass));
104109566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
104113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10412b4937a87SMatthew G. Knepley }
10413b4937a87SMatthew G. Knepley 
10414d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
10415d71ae5a4SJacob Faibussowitsch {
10416bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
10417bd041c0cSMatthew G. Knepley   PetscInt     m, n;
10418bd041c0cSMatthew G. Knepley   void        *ctx;
10419bd041c0cSMatthew G. Knepley   DM           cdm;
10420bd041c0cSMatthew G. Knepley   PetscBool    regular;
10421bd041c0cSMatthew G. Knepley 
10422bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
104233e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
104243e9753d6SMatthew G. Knepley     DM            dmc;
104253e9753d6SMatthew G. Knepley     PetscDS       ds;
10426b4937a87SMatthew G. Knepley     PetscWeakForm wf;
104273e9753d6SMatthew G. Knepley     Vec           u;
104283e9753d6SMatthew G. Knepley     IS            cellIS;
1042906ad1575SMatthew G. Knepley     PetscFormKey  key;
104303e9753d6SMatthew G. Knepley     PetscInt      depth;
104313e9753d6SMatthew G. Knepley 
104329566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
104339566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
104349566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
104359566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
104369566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
10437a102dd69SStefano Zampini     for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
104389566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
104398d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
104409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
104419566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
104429566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
104436528b96dSMatthew G. Knepley     key.label = NULL;
104446528b96dSMatthew G. Knepley     key.value = 0;
104456528b96dSMatthew G. Knepley     key.field = 0;
1044606ad1575SMatthew G. Knepley     key.part  = 0;
10447754e4fbaSMatthew G. Knepley     PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
104489566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
104498d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
104509566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
104513e9753d6SMatthew G. Knepley   } else {
104529566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
104539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
104549566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
104559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10456bd041c0cSMatthew G. Knepley 
104579566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
104589566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
104599566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
104609566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
10461bd041c0cSMatthew G. Knepley 
104629566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
104639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
104649566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
104659566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
104663e9753d6SMatthew G. Knepley   }
104679566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
104683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10469bd041c0cSMatthew G. Knepley }
10470bd041c0cSMatthew G. Knepley 
104711898fd5cSMatthew G. Knepley PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv)
104721898fd5cSMatthew G. Knepley {
104731898fd5cSMatthew G. Knepley   PetscSection gsc, gsf;
104741898fd5cSMatthew G. Knepley   PetscInt     m, n;
104751898fd5cSMatthew G. Knepley   void        *ctx;
104761898fd5cSMatthew G. Knepley 
104771898fd5cSMatthew G. Knepley   PetscFunctionBegin;
104781898fd5cSMatthew G. Knepley   PetscCall(DMGetGlobalSection(dmr, &gsf));
104791898fd5cSMatthew G. Knepley   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
104801898fd5cSMatthew G. Knepley   PetscCall(DMGetGlobalSection(dmc, &gsc));
104811898fd5cSMatthew G. Knepley   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
104821898fd5cSMatthew G. Knepley 
104831898fd5cSMatthew G. Knepley   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv));
104841898fd5cSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix"));
104851898fd5cSMatthew G. Knepley   PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
104861898fd5cSMatthew G. Knepley   PetscCall(MatSetType(*derv, dmc->mattype));
104871898fd5cSMatthew G. Knepley 
104881898fd5cSMatthew G. Knepley   PetscCall(DMGetApplicationContext(dmr, &ctx));
104891898fd5cSMatthew G. Knepley   {
104901898fd5cSMatthew G. Knepley     DM            ndmr;
104911898fd5cSMatthew G. Knepley     PetscDS       ds;
104921898fd5cSMatthew G. Knepley     PetscWeakForm wf;
104931898fd5cSMatthew G. Knepley     Vec           u;
104941898fd5cSMatthew G. Knepley     IS            cellIS;
104951898fd5cSMatthew G. Knepley     PetscFormKey  key;
104961898fd5cSMatthew G. Knepley     PetscInt      depth, Nf;
104971898fd5cSMatthew G. Knepley 
104981898fd5cSMatthew G. Knepley     PetscCall(DMClone(dmr, &ndmr));
104991898fd5cSMatthew G. Knepley     PetscCall(DMCopyDisc(dmr, ndmr));
105001898fd5cSMatthew G. Knepley     PetscCall(DMGetDS(ndmr, &ds));
105011898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetWeakForm(ds, &wf));
105021898fd5cSMatthew G. Knepley     PetscCall(PetscWeakFormClear(wf));
105031898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetNumFields(ds, &Nf));
105041898fd5cSMatthew G. Knepley     for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL));
105051898fd5cSMatthew G. Knepley     PetscCall(DMGetLocalVector(ndmr, &u));
105061898fd5cSMatthew G. Knepley     PetscCall(DMPlexGetDepth(ndmr, &depth));
105071898fd5cSMatthew G. Knepley     PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS));
105081898fd5cSMatthew G. Knepley     PetscCall(MatZeroEntries(*derv));
105091898fd5cSMatthew G. Knepley     key.label = NULL;
105101898fd5cSMatthew G. Knepley     key.value = 0;
105111898fd5cSMatthew G. Knepley     key.field = 0;
105121898fd5cSMatthew G. Knepley     key.part  = 0;
105131898fd5cSMatthew G. Knepley     PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL));
105141898fd5cSMatthew G. Knepley     PetscCall(ISDestroy(&cellIS));
105151898fd5cSMatthew G. Knepley     PetscCall(DMRestoreLocalVector(ndmr, &u));
105161898fd5cSMatthew G. Knepley     PetscCall(DMDestroy(&ndmr));
105171898fd5cSMatthew G. Knepley   }
105181898fd5cSMatthew G. Knepley   PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view"));
105191898fd5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
105201898fd5cSMatthew G. Knepley }
105211898fd5cSMatthew G. Knepley 
105220aef6b92SMatthew G. Knepley /*@
105230aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
105240aef6b92SMatthew G. Knepley 
105250aef6b92SMatthew G. Knepley   Input Parameter:
10526a1cb98faSBarry Smith . dm - The `DMPLEX` object
105270aef6b92SMatthew G. Knepley 
105280aef6b92SMatthew G. Knepley   Output Parameter:
105290aef6b92SMatthew G. Knepley . regular - The flag
105300aef6b92SMatthew G. Knepley 
105310aef6b92SMatthew G. Knepley   Level: intermediate
105320aef6b92SMatthew G. Knepley 
105331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
105340aef6b92SMatthew G. Knepley @*/
10535d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
10536d71ae5a4SJacob Faibussowitsch {
105370aef6b92SMatthew G. Knepley   PetscFunctionBegin;
105380aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105394f572ea9SToby Isaac   PetscAssertPointer(regular, 2);
105400aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
105413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105420aef6b92SMatthew G. Knepley }
105430aef6b92SMatthew G. Knepley 
105440aef6b92SMatthew G. Knepley /*@
105450aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
105460aef6b92SMatthew G. Knepley 
105470aef6b92SMatthew G. Knepley   Input Parameters:
10548a1cb98faSBarry Smith + dm      - The `DMPLEX` object
105490aef6b92SMatthew G. Knepley - regular - The flag
105500aef6b92SMatthew G. Knepley 
105510aef6b92SMatthew G. Knepley   Level: intermediate
105520aef6b92SMatthew G. Knepley 
105531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
105540aef6b92SMatthew G. Knepley @*/
10555d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
10556d71ae5a4SJacob Faibussowitsch {
105570aef6b92SMatthew G. Knepley   PetscFunctionBegin;
105580aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105590aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
105603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105610aef6b92SMatthew G. Knepley }
105620aef6b92SMatthew G. Knepley 
10563a68b90caSToby Isaac /*@
10564f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
10565a1cb98faSBarry Smith   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
10566a68b90caSToby Isaac 
10567a1cb98faSBarry Smith   Not Collective
10568a68b90caSToby Isaac 
10569f899ff85SJose E. Roman   Input Parameter:
10570a1cb98faSBarry Smith . dm - The `DMPLEX` object
10571a68b90caSToby Isaac 
10572a68b90caSToby Isaac   Output Parameters:
1057320f4b53cSBarry Smith + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
1057420f4b53cSBarry Smith - anchorIS      - If not `NULL`, set to the list of anchors indexed by `anchorSection`
10575a68b90caSToby Isaac 
10576a68b90caSToby Isaac   Level: intermediate
10577a68b90caSToby Isaac 
105781cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
10579a68b90caSToby Isaac @*/
10580ce78bad3SBarry Smith PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS)
10581d71ae5a4SJacob Faibussowitsch {
10582a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
10583a68b90caSToby Isaac 
10584a68b90caSToby Isaac   PetscFunctionBegin;
10585a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105869566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
10587a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
10588a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
105893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10590a68b90caSToby Isaac }
10591a68b90caSToby Isaac 
10592a68b90caSToby Isaac /*@
10593a4e35b19SJacob Faibussowitsch   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.
10594a68b90caSToby Isaac 
1059520f4b53cSBarry Smith   Collective
10596a68b90caSToby Isaac 
10597a68b90caSToby Isaac   Input Parameters:
10598a1cb98faSBarry Smith + dm            - The `DMPLEX` object
10599a1cb98faSBarry Smith . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
10600a1cb98faSBarry Smith                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10601a1cb98faSBarry Smith - anchorIS      - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10602a68b90caSToby Isaac 
10603a68b90caSToby Isaac   Level: intermediate
10604a68b90caSToby Isaac 
10605a1cb98faSBarry Smith   Notes:
10606a4e35b19SJacob Faibussowitsch   Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to
10607a4e35b19SJacob Faibussowitsch   an outside value, the anchor constraints set a point's degrees of freedom to be a linear
10608a4e35b19SJacob Faibussowitsch   combination of other points' degrees of freedom.
10609a4e35b19SJacob Faibussowitsch 
10610a1cb98faSBarry Smith   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
10611a1cb98faSBarry Smith   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
10612a1cb98faSBarry Smith 
1061320f4b53cSBarry Smith   The reference counts of `anchorSection` and `anchorIS` are incremented.
10614a1cb98faSBarry Smith 
106151cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
10616a68b90caSToby Isaac @*/
10617d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
10618d71ae5a4SJacob Faibussowitsch {
10619a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
10620e228b242SToby Isaac   PetscMPIInt result;
10621a68b90caSToby Isaac 
10622a68b90caSToby Isaac   PetscFunctionBegin;
10623a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10624e228b242SToby Isaac   if (anchorSection) {
10625e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
106269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
106271dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
10628e228b242SToby Isaac   }
10629e228b242SToby Isaac   if (anchorIS) {
10630e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
106319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
106321dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
10633e228b242SToby Isaac   }
10634a68b90caSToby Isaac 
106359566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
106369566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
10637a68b90caSToby Isaac   plex->anchorSection = anchorSection;
10638a68b90caSToby Isaac 
106399566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
106409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
10641a68b90caSToby Isaac   plex->anchorIS = anchorIS;
10642a68b90caSToby Isaac 
10643cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
10644a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
10645a68b90caSToby Isaac     const PetscInt *anchors;
10646a68b90caSToby Isaac 
106479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
106489566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
106499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
10650a68b90caSToby Isaac     for (a = 0; a < size; a++) {
10651a68b90caSToby Isaac       PetscInt p;
10652a68b90caSToby Isaac 
10653a68b90caSToby Isaac       p = anchors[a];
10654a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
10655a68b90caSToby Isaac         PetscInt dof;
10656a68b90caSToby Isaac 
106579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10658a68b90caSToby Isaac         if (dof) {
106599566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
1066063a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
10661a68b90caSToby Isaac         }
10662a68b90caSToby Isaac       }
10663a68b90caSToby Isaac     }
106649566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
10665a68b90caSToby Isaac   }
10666f7c74593SToby Isaac   /* reset the generic constraints */
106679566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
106683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10669a68b90caSToby Isaac }
10670a68b90caSToby Isaac 
10671d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
10672d71ae5a4SJacob Faibussowitsch {
10673f7c74593SToby Isaac   PetscSection anchorSection;
106746995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
10675a68b90caSToby Isaac 
10676a68b90caSToby Isaac   PetscFunctionBegin;
10677a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
106789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
106799566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
106809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
106816995de1eSToby Isaac   if (numFields) {
10682719ab38cSToby Isaac     PetscInt f;
106839566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
10684719ab38cSToby Isaac 
10685719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
10686719ab38cSToby Isaac       PetscInt numComp;
10687719ab38cSToby Isaac 
106889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
106899566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
10690719ab38cSToby Isaac     }
106916995de1eSToby Isaac   }
106929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
106939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
106946995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
106956995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
106966995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
106979566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
10698a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
106999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10700a68b90caSToby Isaac     if (dof) {
107019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
107029566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
10703a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
107049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
107059566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
10706a68b90caSToby Isaac       }
10707a68b90caSToby Isaac     }
10708a68b90caSToby Isaac   }
107099566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
107109566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
107113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10712a68b90caSToby Isaac }
10713a68b90caSToby Isaac 
10714d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
10715d71ae5a4SJacob Faibussowitsch {
10716f7c74593SToby Isaac   PetscSection    aSec;
10717ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
107180ac89760SToby Isaac   const PetscInt *anchors;
107190ac89760SToby Isaac   PetscInt        numFields, f;
1072066ad2231SToby Isaac   IS              aIS;
10721e19f7ee6SMark Adams   MatType         mtype;
10722e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
107230ac89760SToby Isaac 
107240ac89760SToby Isaac   PetscFunctionBegin;
107250ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
107269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
107279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
107289566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
107299566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
107309566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
107319566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
107329566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
107339566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
10734e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
10735e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
10736e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
107379566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
107389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
107399566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
107406995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
107419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
107429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
107439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
107440ac89760SToby Isaac   i[0] = 0;
107459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
107460ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
10747f19733c5SToby Isaac     PetscInt rDof, rOff, r;
10748f19733c5SToby Isaac 
107499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10750f19733c5SToby Isaac     if (!rDof) continue;
107519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
107520ac89760SToby Isaac     if (numFields) {
107530ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
107540ac89760SToby Isaac         annz = 0;
10755f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
10756f19733c5SToby Isaac           a = anchors[rOff + r];
10757ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
107589566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
107590ac89760SToby Isaac           annz += aDof;
107600ac89760SToby Isaac         }
107619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
107629566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10763ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
107640ac89760SToby Isaac       }
107652f7452b8SBarry Smith     } else {
107660ac89760SToby Isaac       annz = 0;
107679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
107680ac89760SToby Isaac       for (q = 0; q < dof; q++) {
10769ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
10770ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
107719566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
107720ac89760SToby Isaac         annz += aDof;
107730ac89760SToby Isaac       }
107749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
107759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10776ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
107770ac89760SToby Isaac     }
107780ac89760SToby Isaac   }
107790ac89760SToby Isaac   nnz = i[m];
107809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
107810ac89760SToby Isaac   offset = 0;
107820ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
107830ac89760SToby Isaac     if (numFields) {
107840ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
107859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
107860ac89760SToby Isaac         for (q = 0; q < dof; q++) {
107870ac89760SToby Isaac           PetscInt rDof, rOff, r;
107889566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
107899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
107900ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
107910ac89760SToby Isaac             PetscInt s;
107920ac89760SToby Isaac 
107930ac89760SToby Isaac             a = anchors[rOff + r];
10794ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
107959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
107969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10797ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
107980ac89760SToby Isaac           }
107990ac89760SToby Isaac         }
108000ac89760SToby Isaac       }
108012f7452b8SBarry Smith     } else {
108029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
108030ac89760SToby Isaac       for (q = 0; q < dof; q++) {
108040ac89760SToby Isaac         PetscInt rDof, rOff, r;
108059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
108069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
108070ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
108080ac89760SToby Isaac           PetscInt s;
108090ac89760SToby Isaac 
108100ac89760SToby Isaac           a = anchors[rOff + r];
10811ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
108129566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
108139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10814ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
108150ac89760SToby Isaac         }
108160ac89760SToby Isaac       }
108170ac89760SToby Isaac     }
108180ac89760SToby Isaac   }
108199566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
108209566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
108219566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
108229566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
108233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
108240ac89760SToby Isaac }
108250ac89760SToby Isaac 
10826d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10827d71ae5a4SJacob Faibussowitsch {
10828f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
10829f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
1083066ad2231SToby Isaac   Mat          cMat;
1083166ad2231SToby Isaac 
1083266ad2231SToby Isaac   PetscFunctionBegin;
1083366ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
108349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
1083566ad2231SToby Isaac   if (anchorSection) {
1083644a7f3ddSMatthew G. Knepley     PetscInt Nf;
10837e228b242SToby Isaac 
108389566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
108399566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
108409566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
108419566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
108429566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
108439566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
108449566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
108459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
1084666ad2231SToby Isaac   }
108473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1084866ad2231SToby Isaac }
10849a93c429eSMatthew G. Knepley 
10850d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10851d71ae5a4SJacob Faibussowitsch {
10852a93c429eSMatthew G. Knepley   IS           subis;
10853a93c429eSMatthew G. Knepley   PetscSection section, subsection;
10854a93c429eSMatthew G. Knepley 
10855a93c429eSMatthew G. Knepley   PetscFunctionBegin;
108569566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1085728b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
1085828b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10859a93c429eSMatthew G. Knepley   /* Create subdomain */
1086071f1c950SStefano Zampini   PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, PetscObjectComm((PetscObject)dm), NULL, subdm));
10861a93c429eSMatthew G. Knepley   /* Create submodel */
108629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
108639566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
108649566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
108659566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
108669566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
10867a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
10868a93c429eSMatthew G. Knepley   if (is) {
10869a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
10870a93c429eSMatthew G. Knepley     IS              spIS;
10871a93c429eSMatthew G. Knepley     const PetscInt *spmap;
10872a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
10873a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10874a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10875a93c429eSMatthew G. Knepley 
108769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
108779566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
108789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
108799566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
108809566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
108819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10882a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10883a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10884a93c429eSMatthew G. Knepley 
108859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10886a93c429eSMatthew G. Knepley       if (gdof > 0) {
10887a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10888a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10889a93c429eSMatthew G. Knepley 
108909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
108919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10892a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10893a93c429eSMatthew G. Knepley         }
10894a93c429eSMatthew G. Knepley         subSize += pSubSize;
10895a93c429eSMatthew G. Knepley         if (pSubSize) {
10896a93c429eSMatthew G. Knepley           if (bs < 0) {
10897a93c429eSMatthew G. Knepley             bs = pSubSize;
10898a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10899a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10900a93c429eSMatthew G. Knepley             bs = 1;
10901a93c429eSMatthew G. Knepley           }
10902a93c429eSMatthew G. Knepley         }
10903a93c429eSMatthew G. Knepley       }
10904a93c429eSMatthew G. Knepley     }
10905a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
109061690c2aeSBarry Smith     bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
109079371c9d4SSatish Balay     bsLocal[1] = bs;
109089566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
109099371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
109109371c9d4SSatish Balay       bs = 1;
109119371c9d4SSatish Balay     } else {
109129371c9d4SSatish Balay       bs = bsMinMax[0];
109139371c9d4SSatish Balay     }
109149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10915a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10916a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10917a93c429eSMatthew G. Knepley 
109189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10919a93c429eSMatthew G. Knepley       if (gdof > 0) {
10920a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10921a93c429eSMatthew G. Knepley 
109229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10923a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10924a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10925a93c429eSMatthew G. Knepley 
10926a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10927a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
109289566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
109299566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10930a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10931a93c429eSMatthew G. Knepley           }
109329566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
109339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10934ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10935a93c429eSMatthew G. Knepley         }
10936a93c429eSMatthew G. Knepley       }
10937a93c429eSMatthew G. Knepley     }
109389566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
109399566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10940a93c429eSMatthew G. Knepley     if (bs > 1) {
10941a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10942a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10943a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10944a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
109459371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
109469371c9d4SSatish Balay             set = 0;
109479371c9d4SSatish Balay             break;
109489371c9d4SSatish Balay           }
10949a93c429eSMatthew G. Knepley         }
10950a93c429eSMatthew G. Knepley       }
109519566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10952a93c429eSMatthew G. Knepley     }
109534758e3ceSMatthew G. Knepley     // Attach nullspace
109544758e3ceSMatthew G. Knepley     if (dm->nullspaceConstructors) {
10955a93c429eSMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
10956a93c429eSMatthew G. Knepley         (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10957a93c429eSMatthew G. Knepley         if ((*subdm)->nullspaceConstructors[f]) break;
10958a93c429eSMatthew G. Knepley       }
10959a93c429eSMatthew G. Knepley       if (f < Nf) {
10960a93c429eSMatthew G. Knepley         MatNullSpace nullSpace;
109619566063dSJacob Faibussowitsch         PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
109626823f3c5SBlaise Bourdin 
109639566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
109649566063dSJacob Faibussowitsch         PetscCall(MatNullSpaceDestroy(&nullSpace));
10965a93c429eSMatthew G. Knepley       }
10966a93c429eSMatthew G. Knepley     }
109674758e3ceSMatthew G. Knepley   }
109683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10969a93c429eSMatthew G. Knepley }
10970c0f0dcc3SMatthew G. Knepley 
10971c0f0dcc3SMatthew G. Knepley /*@
10972c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10973c0f0dcc3SMatthew G. Knepley 
10974a1cb98faSBarry Smith   Input Parameters:
10975a1cb98faSBarry Smith + dm     - The `DM`
109762a8381b2SBarry Smith - unused - unused argument
10977a1cb98faSBarry Smith 
10978a1cb98faSBarry Smith   Options Database Key:
10979a1cb98faSBarry Smith . -dm_plex_monitor_throughput - Activate the monitor
10980c0f0dcc3SMatthew G. Knepley 
10981c0f0dcc3SMatthew G. Knepley   Level: developer
10982c0f0dcc3SMatthew G. Knepley 
109831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10984c0f0dcc3SMatthew G. Knepley @*/
109852a8381b2SBarry Smith PetscErrorCode DMPlexMonitorThroughput(DM dm, void *unused)
10986d71ae5a4SJacob Faibussowitsch {
10987b665b14eSToby Isaac   PetscLogHandler default_handler;
10988b665b14eSToby Isaac 
109892611ad71SToby Isaac   PetscFunctionBegin;
109902611ad71SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10991b665b14eSToby Isaac   PetscCall(PetscLogGetDefaultHandler(&default_handler));
10992b665b14eSToby Isaac   if (default_handler) {
10993c0f0dcc3SMatthew G. Knepley     PetscLogEvent      event;
10994c0f0dcc3SMatthew G. Knepley     PetscEventPerfInfo eventInfo;
10995835f2295SStefano Zampini     PetscLogDouble     cellRate, flopRate;
10996c0f0dcc3SMatthew G. Knepley     PetscInt           cStart, cEnd, Nf, N;
10997c0f0dcc3SMatthew G. Knepley     const char        *name;
10998c0f0dcc3SMatthew G. Knepley 
109999566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
110009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
110019566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
110029566063dSJacob Faibussowitsch     PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
11003b665b14eSToby Isaac     PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo));
11004c0f0dcc3SMatthew G. Knepley     N        = (cEnd - cStart) * Nf * eventInfo.count;
11005c0f0dcc3SMatthew G. Knepley     flopRate = eventInfo.flops / eventInfo.time;
11006c0f0dcc3SMatthew G. Knepley     cellRate = N / eventInfo.time;
11007835f2295SStefano 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));
110082611ad71SToby Isaac   } else {
11009b665b14eSToby 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.");
110102611ad71SToby Isaac   }
110113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11012c0f0dcc3SMatthew G. Knepley }
11013