xref: /petsc/src/dm/impls/plex/plex.c (revision 6497c311e7b976d467be1503c1effce92a60525c)
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 */
1402f7d72cSksagiyam PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad;
15172ee266SJed Brown PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;
16552f7358SJed Brown 
17f39ec787SMatthew G. Knepley PetscBool  Plexcite       = PETSC_FALSE;
18f39ec787SMatthew G. Knepley const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n"
19f39ec787SMatthew G. Knepley                             "title     = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n"
20f39ec787SMatthew G. Knepley                             "author    = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n"
21f39ec787SMatthew G. Knepley                             "journal   = {SIAM Journal on Scientific Computing},\n"
22f39ec787SMatthew G. Knepley                             "volume    = {38},\n"
23f39ec787SMatthew G. Knepley                             "number    = {5},\n"
24f39ec787SMatthew G. Knepley                             "pages     = {S143--S155},\n"
25f39ec787SMatthew G. Knepley                             "eprint    = {http://arxiv.org/abs/1506.07749},\n"
26f39ec787SMatthew G. Knepley                             "doi       = {10.1137/15M1026092},\n"
27f39ec787SMatthew G. Knepley                             "year      = {2016},\n"
28f39ec787SMatthew G. Knepley                             "petsc_uses={DMPlex},\n}\n";
29f39ec787SMatthew G. Knepley 
305a576424SJed Brown PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
31552f7358SJed Brown 
32e5337592SStefano Zampini /*@
339318fe57SMatthew G. Knepley   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
349318fe57SMatthew G. Knepley 
359318fe57SMatthew G. Knepley   Input Parameter:
36a1cb98faSBarry Smith . dm - The `DMPLEX` object
379318fe57SMatthew G. Knepley 
389318fe57SMatthew G. Knepley   Output Parameter:
399318fe57SMatthew G. Knepley . simplex - Flag checking for a simplex
409318fe57SMatthew G. Knepley 
419318fe57SMatthew G. Knepley   Level: intermediate
429318fe57SMatthew G. Knepley 
43a1cb98faSBarry Smith   Note:
44a1cb98faSBarry Smith   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
45a1cb98faSBarry Smith   If the mesh has no cells, this returns `PETSC_FALSE`.
46a1cb98faSBarry Smith 
471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
489318fe57SMatthew G. Knepley @*/
49d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
50d71ae5a4SJacob Faibussowitsch {
519318fe57SMatthew G. Knepley   DMPolytopeType ct;
529318fe57SMatthew G. Knepley   PetscInt       cStart, cEnd;
539318fe57SMatthew G. Knepley 
549318fe57SMatthew G. Knepley   PetscFunctionBegin;
559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
569371c9d4SSatish Balay   if (cEnd <= cStart) {
579371c9d4SSatish Balay     *simplex = PETSC_FALSE;
583ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
599371c9d4SSatish Balay   }
609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
619318fe57SMatthew G. Knepley   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
639318fe57SMatthew G. Knepley }
649318fe57SMatthew G. Knepley 
659318fe57SMatthew G. Knepley /*@
66412e9a14SMatthew G. Knepley   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
67e5337592SStefano Zampini 
68d8d19677SJose E. Roman   Input Parameters:
69a1cb98faSBarry Smith + dm     - The `DMPLEX` object
70412e9a14SMatthew G. Knepley - height - The cell height in the Plex, 0 is the default
71e5337592SStefano Zampini 
72e5337592SStefano Zampini   Output Parameters:
73412e9a14SMatthew G. Knepley + cStart - The first "normal" cell
7440196513SBarry Smith - cEnd   - The upper bound on "normal" cells
75e5337592SStefano Zampini 
76412e9a14SMatthew G. Knepley   Level: developer
77e5337592SStefano Zampini 
78a1cb98faSBarry Smith   Note:
795ae96e2bSMatthew G. Knepley   This function requires that tensor cells are ordered last.
80a1cb98faSBarry Smith 
812827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
82e5337592SStefano Zampini @*/
83d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
84d71ae5a4SJacob Faibussowitsch {
855ae96e2bSMatthew G. Knepley   DMLabel         ctLabel;
865ae96e2bSMatthew G. Knepley   IS              valueIS;
875ae96e2bSMatthew G. Knepley   const PetscInt *ctypes;
885e27db3eSMatthew G. Knepley   PetscBool       found = PETSC_FALSE;
895ae96e2bSMatthew G. Knepley   PetscInt        Nct, cS = PETSC_MAX_INT, cE = 0;
90e5337592SStefano Zampini 
91e5337592SStefano Zampini   PetscFunctionBegin;
929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
935ae96e2bSMatthew G. Knepley   PetscCall(DMLabelGetValueIS(ctLabel, &valueIS));
945ae96e2bSMatthew G. Knepley   PetscCall(ISGetLocalSize(valueIS, &Nct));
955ae96e2bSMatthew G. Knepley   PetscCall(ISGetIndices(valueIS, &ctypes));
965ae96e2bSMatthew G. Knepley   for (PetscInt t = 0; t < Nct; ++t) {
97c306944fSJed Brown     const DMPolytopeType ct = (DMPolytopeType)ctypes[t];
985ae96e2bSMatthew G. Knepley     PetscInt             ctS, ctE, ht;
995ae96e2bSMatthew G. Knepley 
1005ae96e2bSMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) {
1015ae96e2bSMatthew G. Knepley       // If any cells are not typed, just use all cells
1025ae96e2bSMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd));
1035ae96e2bSMatthew G. Knepley       break;
1045ae96e2bSMatthew G. Knepley     }
105c306944fSJed Brown     if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue;
1065ae96e2bSMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE));
1075ae96e2bSMatthew G. Knepley     if (ctS >= ctE) continue;
1085ae96e2bSMatthew G. Knepley     // Check that a point has the right height
1095ae96e2bSMatthew G. Knepley     PetscCall(DMPlexGetPointHeight(dm, ctS, &ht));
1105ae96e2bSMatthew G. Knepley     if (ht != height) continue;
1115ae96e2bSMatthew G. Knepley     cS    = PetscMin(cS, ctS);
1125ae96e2bSMatthew G. Knepley     cE    = PetscMax(cE, ctE);
1135e27db3eSMatthew G. Knepley     found = PETSC_TRUE;
1145ae96e2bSMatthew G. Knepley   }
1155e27db3eSMatthew G. Knepley   if (!Nct || !found) cS = cE = 0;
1165ae96e2bSMatthew G. Knepley   PetscCall(ISDestroy(&valueIS));
117695799ffSMatthew G. Knepley   // Reset label for fast lookup
118695799ffSMatthew G. Knepley   PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
119412e9a14SMatthew G. Knepley   if (cStart) *cStart = cS;
120412e9a14SMatthew G. Knepley   if (cEnd) *cEnd = cE;
1213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122e5337592SStefano Zampini }
123e5337592SStefano Zampini 
1249c600e38SMatt McGurn PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft)
1259c600e38SMatt McGurn {
1269c600e38SMatt McGurn   PetscInt                 cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t;
1279c600e38SMatt McGurn   PetscInt                *sStart, *sEnd;
1289c600e38SMatt McGurn   PetscViewerVTKFieldType *ft;
1299c600e38SMatt McGurn   PetscInt                 vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1];
1309c600e38SMatt McGurn   DMLabel                  depthLabel, ctLabel;
1319c600e38SMatt McGurn 
1329c600e38SMatt McGurn   PetscFunctionBegin;
1339c600e38SMatt McGurn   /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */
1349c600e38SMatt McGurn   PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1));
1359c600e38SMatt McGurn   PetscCall(DMGetCoordinateDim(dm, &cdim));
1369c600e38SMatt McGurn   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1379c600e38SMatt McGurn   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1389c600e38SMatt McGurn   if (field >= 0) {
1399c600e38SMatt McGurn     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES]));
1409c600e38SMatt McGurn   } else {
1419c600e38SMatt McGurn     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES]));
1429c600e38SMatt McGurn   }
1439c600e38SMatt McGurn 
1449c600e38SMatt McGurn   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1459c600e38SMatt McGurn   PetscCall(DMPlexGetDepth(dm, &depth));
1469c600e38SMatt McGurn   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
1479c600e38SMatt McGurn   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
1489c600e38SMatt McGurn   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
1499c600e38SMatt McGurn     const DMPolytopeType ict = (DMPolytopeType)c;
1509c600e38SMatt McGurn     PetscInt             dep;
1519c600e38SMatt McGurn 
1529c600e38SMatt McGurn     if (ict == DM_POLYTOPE_FV_GHOST) continue;
1539c600e38SMatt McGurn     PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
1549c600e38SMatt McGurn     if (pStart >= 0) {
1559c600e38SMatt McGurn       PetscCall(DMLabelGetValue(depthLabel, cStart, &dep));
1569c600e38SMatt McGurn       if (dep != depth - cellHeight) continue;
1579c600e38SMatt McGurn     }
1589c600e38SMatt McGurn     if (field >= 0) {
1599c600e38SMatt McGurn       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c]));
1609c600e38SMatt McGurn     } else {
1619c600e38SMatt McGurn       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c]));
1629c600e38SMatt McGurn     }
1639c600e38SMatt McGurn   }
1649c600e38SMatt McGurn 
1659c600e38SMatt McGurn   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1669c600e38SMatt McGurn   *types = 0;
1679c600e38SMatt McGurn 
1689c600e38SMatt McGurn   for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) {
1699c600e38SMatt McGurn     if (globalvcdof[c]) ++(*types);
1709c600e38SMatt McGurn   }
1719c600e38SMatt McGurn 
1729c600e38SMatt McGurn   PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft));
1739c600e38SMatt McGurn   t = 0;
1749c600e38SMatt McGurn   if (globalvcdof[DM_NUM_POLYTOPES]) {
1759c600e38SMatt McGurn     sStart[t] = vStart;
1769c600e38SMatt McGurn     sEnd[t]   = vEnd;
1779c600e38SMatt McGurn     ft[t]     = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
1789c600e38SMatt McGurn     ++t;
1799c600e38SMatt McGurn   }
1809c600e38SMatt McGurn 
1819c600e38SMatt McGurn   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
1829c600e38SMatt McGurn     if (globalvcdof[c]) {
1839c600e38SMatt McGurn       const DMPolytopeType ict = (DMPolytopeType)c;
1849c600e38SMatt McGurn 
1859c600e38SMatt McGurn       PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
1869c600e38SMatt McGurn       sStart[t] = cStart;
1879c600e38SMatt McGurn       sEnd[t]   = cEnd;
1889c600e38SMatt McGurn       ft[t]     = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD;
1899c600e38SMatt McGurn       ++t;
1909c600e38SMatt McGurn     }
1919c600e38SMatt McGurn   }
1929c600e38SMatt McGurn 
1934ad8454bSPierre Jolivet   if (!*types) {
1949c600e38SMatt McGurn     if (field >= 0) {
1959c600e38SMatt McGurn       const char *fieldname;
1969c600e38SMatt McGurn 
1979c600e38SMatt McGurn       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
1989c600e38SMatt McGurn       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
1999c600e38SMatt McGurn     } else {
2009c600e38SMatt McGurn       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
2019c600e38SMatt McGurn     }
2029c600e38SMatt McGurn   }
2039c600e38SMatt McGurn 
2049c600e38SMatt McGurn   *ssStart = sStart;
2059c600e38SMatt McGurn   *ssEnd   = sEnd;
2069c600e38SMatt McGurn   *sft     = ft;
2079c600e38SMatt McGurn   PetscFunctionReturn(PETSC_SUCCESS);
2089c600e38SMatt McGurn }
2099c600e38SMatt McGurn 
2109c600e38SMatt McGurn PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft)
2119c600e38SMatt McGurn {
2129c600e38SMatt McGurn   PetscFunctionBegin;
2139c600e38SMatt McGurn   PetscCall(PetscFree3(*sStart, *sEnd, *ft));
2149c600e38SMatt McGurn   PetscFunctionReturn(PETSC_SUCCESS);
2159c600e38SMatt McGurn }
2169c600e38SMatt McGurn 
217d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
218d71ae5a4SJacob Faibussowitsch {
219412e9a14SMatthew G. Knepley   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
220a99a26bcSAdrian Croucher   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
2217e42fee7SMatthew G. Knepley 
2227e42fee7SMatthew G. Knepley   PetscFunctionBegin;
223e630c359SToby Isaac   *ft = PETSC_VTK_INVALID;
2249566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
2259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
2279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
2287e42fee7SMatthew G. Knepley   if (field >= 0) {
2299566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
2309566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
2317e42fee7SMatthew G. Knepley   } else {
2329566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
2339566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
2347e42fee7SMatthew G. Knepley   }
235712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
236a99a26bcSAdrian Croucher   if (globalvcdof[0]) {
2377e42fee7SMatthew G. Knepley     *sStart = vStart;
2387e42fee7SMatthew G. Knepley     *sEnd   = vEnd;
239f094498dSMatthew G. Knepley     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
2407e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_POINT_FIELD;
241a99a26bcSAdrian Croucher   } else if (globalvcdof[1]) {
2427e42fee7SMatthew G. Knepley     *sStart = cStart;
2437e42fee7SMatthew G. Knepley     *sEnd   = cEnd;
244f094498dSMatthew G. Knepley     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
2457e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_CELL_FIELD;
246e630c359SToby Isaac   } else {
247e630c359SToby Isaac     if (field >= 0) {
248e630c359SToby Isaac       const char *fieldname;
249e630c359SToby Isaac 
2509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
25163a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
252e630c359SToby Isaac     } else {
25363a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
254e630c359SToby Isaac     }
255e630c359SToby Isaac   }
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2577e42fee7SMatthew G. Knepley }
2587e42fee7SMatthew G. Knepley 
2596913077dSMatthew G. Knepley /*@
2606913077dSMatthew G. Knepley   DMPlexVecView1D - Plot many 1D solutions on the same line graph
2616913077dSMatthew G. Knepley 
26220f4b53cSBarry Smith   Collective
2636913077dSMatthew G. Knepley 
2646913077dSMatthew G. Knepley   Input Parameters:
265a1cb98faSBarry Smith + dm     - The `DMPLEX` object
2666913077dSMatthew G. Knepley . n      - The number of vectors
2676913077dSMatthew G. Knepley . u      - The array of local vectors
268a1cb98faSBarry Smith - viewer - The `PetscViewer`
2696913077dSMatthew G. Knepley 
2706913077dSMatthew G. Knepley   Level: advanced
2716913077dSMatthew G. Knepley 
2721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
2736913077dSMatthew G. Knepley @*/
274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
275d71ae5a4SJacob Faibussowitsch {
2766913077dSMatthew G. Knepley   PetscDS            ds;
2776913077dSMatthew G. Knepley   PetscDraw          draw = NULL;
2786913077dSMatthew G. Knepley   PetscDrawLG        lg;
2796913077dSMatthew G. Knepley   Vec                coordinates;
2806913077dSMatthew G. Knepley   const PetscScalar *coords, **sol;
2816913077dSMatthew G. Knepley   PetscReal         *vals;
2826913077dSMatthew G. Knepley   PetscInt          *Nc;
2836913077dSMatthew G. Knepley   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
2846913077dSMatthew G. Knepley   char             **names;
2856913077dSMatthew G. Knepley 
2866913077dSMatthew G. Knepley   PetscFunctionBegin;
2879566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
2889566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
2899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
2909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponents(ds, &Nc));
2916913077dSMatthew G. Knepley 
2929566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2933ba16761SJacob Faibussowitsch   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
2949566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
2956913077dSMatthew G. Knepley 
2969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
2976913077dSMatthew G. Knepley   for (i = 0, l = 0; i < n; ++i) {
2986913077dSMatthew G. Knepley     const char *vname;
2996913077dSMatthew G. Knepley 
3009566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
3016913077dSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
3026913077dSMatthew G. Knepley       PetscObject disc;
3036913077dSMatthew G. Knepley       const char *fname;
3046913077dSMatthew G. Knepley       char        tmpname[PETSC_MAX_PATH_LEN];
3056913077dSMatthew G. Knepley 
3069566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
3076913077dSMatthew G. Knepley       /* TODO Create names for components */
3086913077dSMatthew G. Knepley       for (c = 0; c < Nc[f]; ++c, ++l) {
3099566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(disc, &fname));
310c6a7a370SJeremy L Thompson         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
311c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
312c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
3139566063dSJacob Faibussowitsch         PetscCall(PetscStrallocpy(tmpname, &names[l]));
3146913077dSMatthew G. Knepley       }
3156913077dSMatthew G. Knepley     }
3166913077dSMatthew G. Knepley   }
3179566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
3186913077dSMatthew G. Knepley   /* Just add P_1 support for now */
3199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3209566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3219566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
3229566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
3236913077dSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
3246913077dSMatthew G. Knepley     PetscScalar *x, *svals;
3256913077dSMatthew G. Knepley 
3269566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
3276913077dSMatthew G. Knepley     for (i = 0; i < n; ++i) {
3289566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
3296913077dSMatthew G. Knepley       for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
3306913077dSMatthew G. Knepley     }
3319566063dSJacob Faibussowitsch     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
3326913077dSMatthew G. Knepley   }
3339566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
3349566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
3359566063dSJacob Faibussowitsch   for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
3369566063dSJacob Faibussowitsch   PetscCall(PetscFree3(sol, names, vals));
3376913077dSMatthew G. Knepley 
3389566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDraw(lg));
3399566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDestroy(&lg));
3403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3416913077dSMatthew G. Knepley }
3426913077dSMatthew G. Knepley 
343d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
344d71ae5a4SJacob Faibussowitsch {
3456913077dSMatthew G. Knepley   DM dm;
3466913077dSMatthew G. Knepley 
3476913077dSMatthew G. Knepley   PetscFunctionBegin;
3489566063dSJacob Faibussowitsch   PetscCall(VecGetDM(u, &dm));
3499566063dSJacob Faibussowitsch   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
3503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3516913077dSMatthew G. Knepley }
3526913077dSMatthew G. Knepley 
353d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
354d71ae5a4SJacob Faibussowitsch {
355e412dcbdSMatthew G. Knepley   DM                 dm;
356d1df6f1dSMatthew G. Knepley   PetscSection       s;
357e412dcbdSMatthew G. Knepley   PetscDraw          draw, popup;
358e412dcbdSMatthew G. Knepley   DM                 cdm;
359e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
360e412dcbdSMatthew G. Knepley   Vec                coordinates;
361c9c77995SMatthew G. Knepley   const PetscScalar *array;
362c9c77995SMatthew G. Knepley   PetscReal          lbound[3], ubound[3];
363339e3443SMatthew G. Knepley   PetscReal          vbound[2], time;
3646913077dSMatthew G. Knepley   PetscBool          flg;
365d1df6f1dSMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
366e412dcbdSMatthew G. Knepley   const char        *name;
367339e3443SMatthew G. Knepley   char               title[PETSC_MAX_PATH_LEN];
368e412dcbdSMatthew G. Knepley 
369e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
3709566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3719566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
3729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
3739566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
3749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
3759566063dSJacob Faibussowitsch   PetscCall(DMGetCoarsenLevel(dm, &level));
3769566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
3779566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
3789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
381e412dcbdSMatthew G. Knepley 
3829566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
3839566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
384e412dcbdSMatthew G. Knepley 
3859566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
386c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
3879566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
388e412dcbdSMatthew G. Knepley 
389d1df6f1dSMatthew G. Knepley   /* Could implement something like DMDASelectFields() */
390d1df6f1dSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
391d1df6f1dSMatthew G. Knepley     DM          fdm = dm;
392d1df6f1dSMatthew G. Knepley     Vec         fv  = v;
393d1df6f1dSMatthew G. Knepley     IS          fis;
394d1df6f1dSMatthew G. Knepley     char        prefix[PETSC_MAX_PATH_LEN];
395d1df6f1dSMatthew G. Knepley     const char *fname;
396d1df6f1dSMatthew G. Knepley 
3979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
3989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(s, f, &fname));
399d1df6f1dSMatthew G. Knepley 
4009566063dSJacob Faibussowitsch     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
401ad540459SPierre Jolivet     else prefix[0] = '\0';
402d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
4039566063dSJacob Faibussowitsch       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
4049566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(v, fis, &fv));
4059566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
4069566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
407d1df6f1dSMatthew G. Knepley     }
408d1df6f1dSMatthew G. Knepley     for (comp = 0; comp < Nc; ++comp, ++w) {
409d1df6f1dSMatthew G. Knepley       PetscInt nmax = 2;
410d1df6f1dSMatthew G. Knepley 
4119566063dSJacob Faibussowitsch       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
41263a3b9bcSJacob Faibussowitsch       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
41363a3b9bcSJacob Faibussowitsch       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
4149566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetTitle(draw, title));
415d1df6f1dSMatthew G. Knepley 
416d1df6f1dSMatthew G. Knepley       /* TODO Get max and min only for this component */
4179566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
418339e3443SMatthew G. Knepley       if (!flg) {
4199566063dSJacob Faibussowitsch         PetscCall(VecMin(fv, NULL, &vbound[0]));
4209566063dSJacob Faibussowitsch         PetscCall(VecMax(fv, NULL, &vbound[1]));
421d1df6f1dSMatthew G. Knepley         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
422339e3443SMatthew G. Knepley       }
423c9c77995SMatthew G. Knepley 
4249566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetPopup(draw, &popup));
4259566063dSJacob Faibussowitsch       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
426c9c77995SMatthew G. Knepley       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
4279566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(fv, &array));
428e412dcbdSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
429b7550097SMatthew G. Knepley         DMPolytopeType     ct;
43099a2f7bcSMatthew G. Knepley         PetscScalar       *coords = NULL, *a = NULL;
431c9c77995SMatthew G. Knepley         const PetscScalar *coords_arr;
432c9c77995SMatthew G. Knepley         PetscBool          isDG;
433*6497c311SBarry Smith         PetscInt           numCoords;
434*6497c311SBarry Smith         int                color[4] = {-1, -1, -1, -1};
435e412dcbdSMatthew G. Knepley 
436b7550097SMatthew G. Knepley         PetscCall(DMPlexGetCellType(dm, c, &ct));
4379566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
438339e3443SMatthew G. Knepley         if (a) {
439d1df6f1dSMatthew G. Knepley           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
440339e3443SMatthew G. Knepley           color[1] = color[2] = color[3] = color[0];
441339e3443SMatthew G. Knepley         } else {
442339e3443SMatthew G. Knepley           PetscScalar *vals = NULL;
443339e3443SMatthew G. Knepley           PetscInt     numVals, va;
444339e3443SMatthew G. Knepley 
4459566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
446b7550097SMatthew G. Knepley           if (!numVals) {
447b7550097SMatthew G. Knepley             PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
448b7550097SMatthew G. Knepley             continue;
449b7550097SMatthew G. Knepley           }
45063a3b9bcSJacob 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);
451d1df6f1dSMatthew G. Knepley           switch (numVals / Nc) {
452b7550097SMatthew G. Knepley           case 1: /* P1 Clamped Segment Prism */
453b7550097SMatthew G. Knepley           case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */
454b7550097SMatthew 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]);
455b7550097SMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
456b7550097SMatthew G. Knepley             break;
457d1df6f1dSMatthew G. Knepley           case 3: /* P1 Triangle */
458d1df6f1dSMatthew G. Knepley           case 4: /* P1 Quadrangle */
459b7550097SMatthew 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]);
460d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
461339e3443SMatthew G. Knepley             break;
462d1df6f1dSMatthew G. Knepley           case 6: /* P2 Triangle */
463d1df6f1dSMatthew G. Knepley           case 8: /* P2 Quadrangle */
464b7550097SMatthew 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]);
465d1df6f1dSMatthew 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]);
466d1df6f1dSMatthew G. Knepley             break;
467d71ae5a4SJacob Faibussowitsch           default:
468d71ae5a4SJacob Faibussowitsch             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
469339e3443SMatthew G. Knepley           }
4709566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
471339e3443SMatthew G. Knepley         }
472c9c77995SMatthew G. Knepley         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
473e412dcbdSMatthew G. Knepley         switch (numCoords) {
474e412dcbdSMatthew G. Knepley         case 6:
4759edc3542SMatthew Knepley         case 12: /* Localized triangle */
4769566063dSJacob 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]));
477e412dcbdSMatthew G. Knepley           break;
478e412dcbdSMatthew G. Knepley         case 8:
4799edc3542SMatthew Knepley         case 16: /* Localized quadrilateral */
480b7550097SMatthew G. Knepley           if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) {
481b7550097SMatthew G. Knepley             PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1])));
482b7550097SMatthew G. Knepley           } else {
4839566063dSJacob 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]));
4849566063dSJacob 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]));
485b7550097SMatthew G. Knepley           }
486e412dcbdSMatthew G. Knepley           break;
487d71ae5a4SJacob Faibussowitsch         default:
488d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
489e412dcbdSMatthew G. Knepley         }
490c9c77995SMatthew G. Knepley         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
491e412dcbdSMatthew G. Knepley       }
4929566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(fv, &array));
4939566063dSJacob Faibussowitsch       PetscCall(PetscDrawFlush(draw));
4949566063dSJacob Faibussowitsch       PetscCall(PetscDrawPause(draw));
4959566063dSJacob Faibussowitsch       PetscCall(PetscDrawSave(draw));
496d1df6f1dSMatthew G. Knepley     }
497d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
4989566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(v, fis, &fv));
4999566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&fis));
5009566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&fdm));
501d1df6f1dSMatthew G. Knepley     }
502d1df6f1dSMatthew G. Knepley   }
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
504e412dcbdSMatthew G. Knepley }
505e412dcbdSMatthew G. Knepley 
506d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
507d71ae5a4SJacob Faibussowitsch {
5086913077dSMatthew G. Knepley   DM        dm;
5096913077dSMatthew G. Knepley   PetscDraw draw;
5106913077dSMatthew G. Knepley   PetscInt  dim;
5116913077dSMatthew G. Knepley   PetscBool isnull;
5126913077dSMatthew G. Knepley 
5136913077dSMatthew G. Knepley   PetscFunctionBegin;
5149566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
5159566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
5163ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
5176913077dSMatthew G. Knepley 
5189566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
5199566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
5206913077dSMatthew G. Knepley   switch (dim) {
521d71ae5a4SJacob Faibussowitsch   case 1:
522d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
523d71ae5a4SJacob Faibussowitsch     break;
524d71ae5a4SJacob Faibussowitsch   case 2:
525d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
526d71ae5a4SJacob Faibussowitsch     break;
527d71ae5a4SJacob Faibussowitsch   default:
528d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
5296913077dSMatthew G. Knepley   }
5303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5316913077dSMatthew G. Knepley }
5326913077dSMatthew G. Knepley 
533d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
534d71ae5a4SJacob Faibussowitsch {
535684b87d9SLisandro Dalcin   DM                      dm;
536684b87d9SLisandro Dalcin   Vec                     locv;
537684b87d9SLisandro Dalcin   const char             *name;
538684b87d9SLisandro Dalcin   PetscSection            section;
539684b87d9SLisandro Dalcin   PetscInt                pStart, pEnd;
540e630c359SToby Isaac   PetscInt                numFields;
541684b87d9SLisandro Dalcin   PetscViewerVTKFieldType ft;
542684b87d9SLisandro Dalcin 
543684b87d9SLisandro Dalcin   PetscFunctionBegin;
5449566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
5459566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
5469566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
5479566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)locv, name));
5489566063dSJacob Faibussowitsch   PetscCall(VecCopy(v, locv));
5499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
5509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
551e630c359SToby Isaac   if (!numFields) {
5529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
5539566063dSJacob Faibussowitsch     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
554e630c359SToby Isaac   } else {
555e630c359SToby Isaac     PetscInt f;
556e630c359SToby Isaac 
557e630c359SToby Isaac     for (f = 0; f < numFields; f++) {
5589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
559e630c359SToby Isaac       if (ft == PETSC_VTK_INVALID) continue;
5609566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)locv));
5619566063dSJacob Faibussowitsch       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
562e630c359SToby Isaac     }
5639566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locv));
564e630c359SToby Isaac   }
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566684b87d9SLisandro Dalcin }
567684b87d9SLisandro Dalcin 
568d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
569d71ae5a4SJacob Faibussowitsch {
570552f7358SJed Brown   DM        dm;
5715f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;
572552f7358SJed Brown 
573552f7358SJed Brown   PetscFunctionBegin;
5749566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
57528b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
5779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5789566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5799566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
5805f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
5815f34f2dcSJed Brown   if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
582684b87d9SLisandro Dalcin     PetscInt    i, numFields;
583684b87d9SLisandro Dalcin     PetscObject fe;
584ef31f671SMatthew G. Knepley     PetscBool   fem  = PETSC_FALSE;
585684b87d9SLisandro Dalcin     Vec         locv = v;
586684b87d9SLisandro Dalcin     const char *name;
587684b87d9SLisandro Dalcin     PetscInt    step;
588684b87d9SLisandro Dalcin     PetscReal   time;
589ef31f671SMatthew G. Knepley 
5909566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &numFields));
591684b87d9SLisandro Dalcin     for (i = 0; i < numFields; i++) {
5929566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, i, NULL, &fe));
5939371c9d4SSatish Balay       if (fe->classid == PETSCFE_CLASSID) {
5949371c9d4SSatish Balay         fem = PETSC_TRUE;
5959371c9d4SSatish Balay         break;
5969371c9d4SSatish Balay       }
597ef31f671SMatthew G. Knepley     }
598684b87d9SLisandro Dalcin     if (fem) {
599798534f6SMatthew G. Knepley       PetscObject isZero;
600798534f6SMatthew G. Knepley 
6019566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &locv));
6029566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)v, &name));
6039566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)locv, name));
6049566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
6059566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
6069566063dSJacob Faibussowitsch       PetscCall(VecCopy(v, locv));
6079566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
6089566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
609ef31f671SMatthew G. Knepley     }
610552f7358SJed Brown     if (isvtk) {
6119566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
612b136c2c9SMatthew G. Knepley     } else if (ishdf5) {
613b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6149566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
615b136c2c9SMatthew G. Knepley #else
616b136c2c9SMatthew G. Knepley       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
617b136c2c9SMatthew G. Knepley #endif
618f13a32a3SMatthew G. Knepley     } else if (isdraw) {
6199566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
620684b87d9SLisandro Dalcin     } else if (isglvis) {
6219566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
6229566063dSJacob Faibussowitsch       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
6239566063dSJacob Faibussowitsch       PetscCall(VecView_GLVis(locv, viewer));
6245f34f2dcSJed Brown     } else if (iscgns) {
6255f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
6265f34f2dcSJed Brown       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
6275f34f2dcSJed Brown #else
6285f34f2dcSJed Brown       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
6295f34f2dcSJed Brown #endif
630684b87d9SLisandro Dalcin     }
631798534f6SMatthew G. Knepley     if (fem) {
6329566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
6339566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &locv));
634798534f6SMatthew G. Knepley     }
635552f7358SJed Brown   } else {
636684b87d9SLisandro Dalcin     PetscBool isseq;
637684b87d9SLisandro Dalcin 
6389566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
6399566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
6409566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
641552f7358SJed Brown   }
6423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
643552f7358SJed Brown }
644552f7358SJed Brown 
645d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
646d71ae5a4SJacob Faibussowitsch {
647552f7358SJed Brown   DM        dm;
6485f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;
649552f7358SJed Brown 
650552f7358SJed Brown   PetscFunctionBegin;
6519566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
65228b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6539566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
6549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6559566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
6569566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
6575f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
6589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
6595f34f2dcSJed Brown   if (isvtk || isdraw || isglvis || iscgns) {
660552f7358SJed Brown     Vec         locv;
661798534f6SMatthew G. Knepley     PetscObject isZero;
662552f7358SJed Brown     const char *name;
663552f7358SJed Brown 
6649566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &locv));
6659566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
6669566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)locv, name));
6679566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
6689566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
6699566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
6709566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
6719566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_Local(locv, viewer));
6729566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
6739566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &locv));
6744d7cf8c0SStefano Zampini     /* Call flush for proper logging of VecView timings */
6754d7cf8c0SStefano Zampini     if (isvtk) PetscCall(PetscViewerFlush(viewer));
676b136c2c9SMatthew G. Knepley   } else if (ishdf5) {
677b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6789566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
679b136c2c9SMatthew G. Knepley #else
680b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
681b136c2c9SMatthew G. Knepley #endif
6826823f3c5SBlaise Bourdin   } else if (isexodusii) {
6836823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
6849566063dSJacob Faibussowitsch     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
6856823f3c5SBlaise Bourdin #else
6866823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
6876823f3c5SBlaise Bourdin #endif
688552f7358SJed Brown   } else {
689684b87d9SLisandro Dalcin     PetscBool isseq;
690684b87d9SLisandro Dalcin 
6919566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
6929566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
6939566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
694552f7358SJed Brown   }
6953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
696552f7358SJed Brown }
697552f7358SJed Brown 
698d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
699d71ae5a4SJacob Faibussowitsch {
700d930f514SMatthew G. Knepley   DM                dm;
701d930f514SMatthew G. Knepley   MPI_Comm          comm;
702d930f514SMatthew G. Knepley   PetscViewerFormat format;
703d930f514SMatthew G. Knepley   Vec               v;
704d930f514SMatthew G. Knepley   PetscBool         isvtk, ishdf5;
705d930f514SMatthew G. Knepley 
706d930f514SMatthew G. Knepley   PetscFunctionBegin;
7079566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
7089566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
70928b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7109566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
7119566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
713d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
714a8ad634aSStefano Zampini     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
715a8ad634aSStefano Zampini     /* this need a better fix */
716a8ad634aSStefano Zampini     if (dm->useNatural) {
717a8ad634aSStefano Zampini       if (dm->sfNatural) {
718d930f514SMatthew G. Knepley         const char *vecname;
719d930f514SMatthew G. Knepley         PetscInt    n, nroots;
720d930f514SMatthew G. Knepley 
7219566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(originalv, &n));
7229566063dSJacob Faibussowitsch         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
723d930f514SMatthew G. Knepley         if (n == nroots) {
724f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
7259566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
7269566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
7279566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
7289566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
729d930f514SMatthew G. Knepley         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
730d930f514SMatthew G. Knepley       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
731a8ad634aSStefano Zampini     } else v = originalv;
732a8ad634aSStefano Zampini   } else v = originalv;
733a8ad634aSStefano Zampini 
734d930f514SMatthew G. Knepley   if (ishdf5) {
735d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
7369566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
737d930f514SMatthew G. Knepley #else
738d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
739d930f514SMatthew G. Knepley #endif
740d930f514SMatthew G. Knepley   } else if (isvtk) {
741d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
742d930f514SMatthew G. Knepley   } else {
743d930f514SMatthew G. Knepley     PetscBool isseq;
744d930f514SMatthew G. Knepley 
7459566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
7469566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
7479566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
748d930f514SMatthew G. Knepley   }
749f16a8b29SMatthew G. Knepley   if (v != originalv) PetscCall(VecDestroy(&v));
7503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
751d930f514SMatthew G. Knepley }
752d930f514SMatthew G. Knepley 
753d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
754d71ae5a4SJacob Faibussowitsch {
7552c40f234SMatthew G. Knepley   DM        dm;
7562c40f234SMatthew G. Knepley   PetscBool ishdf5;
7572c40f234SMatthew G. Knepley 
7582c40f234SMatthew G. Knepley   PetscFunctionBegin;
7599566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
76028b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7622c40f234SMatthew G. Knepley   if (ishdf5) {
7632c40f234SMatthew G. Knepley     DM          dmBC;
7642c40f234SMatthew G. Knepley     Vec         gv;
7652c40f234SMatthew G. Knepley     const char *name;
7662c40f234SMatthew G. Knepley 
7679566063dSJacob Faibussowitsch     PetscCall(DMGetOutputDM(dm, &dmBC));
7689566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmBC, &gv));
7699566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
7709566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)gv, name));
7719566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(gv, viewer));
7729566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
7739566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
7749566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
7751baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
7763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7772c40f234SMatthew G. Knepley }
7782c40f234SMatthew G. Knepley 
779d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
780d71ae5a4SJacob Faibussowitsch {
7812c40f234SMatthew G. Knepley   DM        dm;
7826823f3c5SBlaise Bourdin   PetscBool ishdf5, isexodusii;
7832c40f234SMatthew G. Knepley 
7842c40f234SMatthew G. Knepley   PetscFunctionBegin;
7859566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
78628b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
7892c40f234SMatthew G. Knepley   if (ishdf5) {
790878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
7919566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
792b136c2c9SMatthew G. Knepley #else
793b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
794878b459fSMatthew G. Knepley #endif
7956823f3c5SBlaise Bourdin   } else if (isexodusii) {
7966823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
7979566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
7986823f3c5SBlaise Bourdin #else
7996823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
8006823f3c5SBlaise Bourdin #endif
8011baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
8023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
803552f7358SJed Brown }
804552f7358SJed Brown 
805d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
806d71ae5a4SJacob Faibussowitsch {
807d930f514SMatthew G. Knepley   DM                dm;
808d930f514SMatthew G. Knepley   PetscViewerFormat format;
809d930f514SMatthew G. Knepley   PetscBool         ishdf5;
810d930f514SMatthew G. Knepley 
811d930f514SMatthew G. Knepley   PetscFunctionBegin;
8129566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
81328b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
8149566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
8159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
816d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
817a8ad634aSStefano Zampini     if (dm->useNatural) {
818d930f514SMatthew G. Knepley       if (dm->sfNatural) {
819d930f514SMatthew G. Knepley         if (ishdf5) {
820d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
821d930f514SMatthew G. Knepley           Vec         v;
822d930f514SMatthew G. Knepley           const char *vecname;
823d930f514SMatthew G. Knepley 
824f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
8259566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
8269566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
8279566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
8289566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
8299566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
830f16a8b29SMatthew G. Knepley           PetscCall(VecDestroy(&v));
831d930f514SMatthew G. Knepley #else
832d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
833d930f514SMatthew G. Knepley #endif
834d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
835d930f514SMatthew G. Knepley       }
8361baa6e33SBarry Smith     } else PetscCall(VecLoad_Default(originalv, viewer));
837d930f514SMatthew G. Knepley   }
8383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
839d930f514SMatthew G. Knepley }
840d930f514SMatthew G. Knepley 
841d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
842d71ae5a4SJacob Faibussowitsch {
843731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
844731e8ddeSMatthew G. Knepley   Vec                coordinates;
845ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
846731e8ddeSMatthew G. Knepley   const char        *name[4];
847731e8ddeSMatthew G. Knepley   const PetscScalar *a;
848731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
849731e8ddeSMatthew G. Knepley 
850731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
8519566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
8529566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
8549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
8559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
8569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
8589566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
859731e8ddeSMatthew G. Knepley   name[0]       = "vertex";
860731e8ddeSMatthew G. Knepley   name[1]       = "edge";
861731e8ddeSMatthew G. Knepley   name[dim - 1] = "face";
862731e8ddeSMatthew G. Knepley   name[dim]     = "cell";
863731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
864731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
865ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
866731e8ddeSMatthew G. Knepley 
8679566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
86863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
8699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
871731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
872731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
873731e8ddeSMatthew G. Knepley 
874731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
8759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
876731e8ddeSMatthew G. Knepley       if (!dof) continue;
8779566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
8789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
87963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
880731e8ddeSMatthew G. Knepley       for (p = 0; p < dof / dim; ++p) {
8819566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
882731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
8839566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
8849566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
885731e8ddeSMatthew G. Knepley         }
8869566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
887731e8ddeSMatthew G. Knepley       }
8889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
889731e8ddeSMatthew G. Knepley     }
8909566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8919566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
892731e8ddeSMatthew G. Knepley   }
8939566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
8943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
895731e8ddeSMatthew G. Knepley }
896731e8ddeSMatthew G. Knepley 
8979371c9d4SSatish Balay typedef enum {
8989371c9d4SSatish Balay   CS_CARTESIAN,
8999371c9d4SSatish Balay   CS_POLAR,
9009371c9d4SSatish Balay   CS_CYLINDRICAL,
9019371c9d4SSatish Balay   CS_SPHERICAL
9029371c9d4SSatish Balay } CoordSystem;
90319ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
90419ad8254SMatthew G. Knepley 
905d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
906d71ae5a4SJacob Faibussowitsch {
90719ad8254SMatthew G. Knepley   PetscInt i;
90819ad8254SMatthew G. Knepley 
90919ad8254SMatthew G. Knepley   PetscFunctionBegin;
91019ad8254SMatthew G. Knepley   if (dim > 3) {
9119566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
91219ad8254SMatthew G. Knepley   } else {
913bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
91419ad8254SMatthew G. Knepley 
91519ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
91619ad8254SMatthew G. Knepley     switch (cs) {
9179371c9d4SSatish Balay     case CS_CARTESIAN:
9189371c9d4SSatish Balay       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
9199371c9d4SSatish Balay       break;
92019ad8254SMatthew G. Knepley     case CS_POLAR:
92163a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
92219ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
92319ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
92419ad8254SMatthew G. Knepley       break;
92519ad8254SMatthew G. Knepley     case CS_CYLINDRICAL:
92663a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
92719ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
92819ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
92919ad8254SMatthew G. Knepley       trcoords[2] = coords[2];
93019ad8254SMatthew G. Knepley       break;
93119ad8254SMatthew G. Knepley     case CS_SPHERICAL:
93263a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
93319ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
93419ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
93519ad8254SMatthew G. Knepley       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
93619ad8254SMatthew G. Knepley       break;
93719ad8254SMatthew G. Knepley     }
9389566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
93919ad8254SMatthew G. Knepley   }
9403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
94119ad8254SMatthew G. Knepley }
94219ad8254SMatthew G. Knepley 
943d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
944d71ae5a4SJacob Faibussowitsch {
945552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex *)dm->data;
9466858538eSMatthew G. Knepley   DM                cdm, cdmCell;
9476858538eSMatthew G. Knepley   PetscSection      coordSection, coordSectionCell;
9486858538eSMatthew G. Knepley   Vec               coordinates, coordinatesCell;
949552f7358SJed Brown   PetscViewerFormat format;
950552f7358SJed Brown 
951552f7358SJed Brown   PetscFunctionBegin;
9529566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
953552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
954552f7358SJed Brown     const char *name;
955f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
9569318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
957552f7358SJed Brown     PetscMPIInt rank, size;
958552f7358SJed Brown 
9599f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
9609f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
9619f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
9629f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
9639f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
9649f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
9659566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
9669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
9679566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
9689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
9709566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
97263a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
97363a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
97463a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
97563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
9769566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
97763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
978552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
979552f7358SJed Brown       PetscInt dof, off, s;
980552f7358SJed Brown 
9819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
9829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
98348a46eb9SPierre Jolivet       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
984552f7358SJed Brown     }
9859566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
98663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
98763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
988552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
989552f7358SJed Brown       PetscInt dof, off, c;
990552f7358SJed Brown 
9919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
9929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
99348a46eb9SPierre 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]));
994552f7358SJed Brown     }
9959566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
9969566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
9973d2e540fSStefano Zampini     if (coordSection && coordinates) {
99819ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
9996858538eSMatthew G. Knepley       const PetscScalar *array, *arrayCell = NULL;
10006858538eSMatthew G. Knepley       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
100119ad8254SMatthew G. Knepley       PetscMPIInt        rank;
100219ad8254SMatthew G. Knepley       const char        *name;
100319ad8254SMatthew G. Knepley 
10049566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
10059566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
10069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
100763a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
10089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
10096858538eSMatthew G. Knepley       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
10106858538eSMatthew G. Knepley       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
10116858538eSMatthew G. Knepley       pStart = PetscMin(pvStart, pcStart);
10126858538eSMatthew G. Knepley       pEnd   = PetscMax(pvEnd, pcEnd);
10139566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
101463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
101563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
10169566063dSJacob Faibussowitsch       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
101719ad8254SMatthew G. Knepley 
10189566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordinates, &array));
10196858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
10209566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
10219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
102219ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
102319ad8254SMatthew G. Knepley         PetscInt dof, off;
102419ad8254SMatthew G. Knepley 
10256858538eSMatthew G. Knepley         if (p >= pvStart && p < pvEnd) {
10269566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
10279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
10286858538eSMatthew G. Knepley           if (dof) {
1029f2719977SBarry Smith             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
10309566063dSJacob Faibussowitsch             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
10319566063dSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
103219ad8254SMatthew G. Knepley           }
10336858538eSMatthew G. Knepley         }
10346858538eSMatthew G. Knepley         if (cdmCell && p >= pcStart && p < pcEnd) {
10356858538eSMatthew G. Knepley           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
10366858538eSMatthew G. Knepley           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
10376858538eSMatthew G. Knepley           if (dof) {
1038f2719977SBarry Smith             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
10396858538eSMatthew G. Knepley             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
10406858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
10416858538eSMatthew G. Knepley           }
10426858538eSMatthew G. Knepley         }
10436858538eSMatthew G. Knepley       }
10449566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
10459566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
10469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
10476858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
10483d2e540fSStefano Zampini     }
10499566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
10509566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
10519318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
10529318fe57SMatthew G. Knepley       DMLabel     label;
10539318fe57SMatthew G. Knepley       PetscBool   isdepth;
10549318fe57SMatthew G. Knepley       const char *name;
10559318fe57SMatthew G. Knepley 
10569566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
10579566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
10589318fe57SMatthew G. Knepley       if (isdepth) continue;
10599566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
10609566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
10619318fe57SMatthew G. Knepley     }
1062552f7358SJed Brown     if (size > 1) {
1063552f7358SJed Brown       PetscSF sf;
1064552f7358SJed Brown 
10659566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
10669566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
1067552f7358SJed Brown     }
10681fca310dSJames Wright     if (mesh->periodic.face_sfs)
10691fca310dSJames Wright       for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer));
10709566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1071552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
10720588280cSMatthew G. Knepley     const char  *name, *color;
10730588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
10740588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
1075fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
1076552f7358SJed Brown     PetscReal    scale      = 2.0;
107778081901SStefano Zampini     PetscReal    tikzscale  = 1.0;
1078b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
10790588280cSMatthew G. Knepley     double       tcoords[3];
1080552f7358SJed Brown     PetscScalar *coords;
1081b862f699SMatthew 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;
1082552f7358SJed Brown     PetscMPIInt  rank, size;
10830588280cSMatthew G. Knepley     char       **names, **colors, **lcolors;
1084b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
1085fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
1086fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
1087552f7358SJed Brown 
10889f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
10899f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
10909f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
10919f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
10929f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
10939f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
10949566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
10959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
10969566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
10970588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
10980588280cSMatthew G. Knepley     numColors  = 10;
10990588280cSMatthew G. Knepley     numLColors = 10;
11009566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
11019566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
11029566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
11039566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
1104b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
1105b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
1106b7f6ffafSMatthew G. Knepley     n = 4;
11079566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
11081dca8a05SBarry 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);
1109bd3611e6SMatthew G. Knepley     n = 4;
11109566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
11111dca8a05SBarry 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);
11129566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
11130588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
11149566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
11150588280cSMatthew G. Knepley     if (!useColors) {
11160588280cSMatthew G. Knepley       numColors = 3;
11179566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
11180588280cSMatthew G. Knepley     }
11199566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
11200588280cSMatthew G. Knepley     if (!useColors) {
11210588280cSMatthew G. Knepley       numLColors = 4;
11229566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
11230588280cSMatthew G. Knepley     }
11249566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1125b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
11269566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
11271dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1128202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
11299566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
1130fe1cc32dSStefano Zampini 
1131fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
11329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
11349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
11359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1136b862f699SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
1137fe1cc32dSStefano Zampini     if (lflg) {
1138fe1cc32dSStefano Zampini       DMLabel lbl;
1139fe1cc32dSStefano Zampini 
11409566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
1141fe1cc32dSStefano Zampini       if (lbl) {
1142fe1cc32dSStefano Zampini         PetscInt val, defval;
1143fe1cc32dSStefano Zampini 
11449566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
11459566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1146fe1cc32dSStefano Zampini         for (c = pStart; c < pEnd; c++) {
1147fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
1148fe1cc32dSStefano Zampini           PetscInt  closureSize;
1149fe1cc32dSStefano Zampini 
11509566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
1151fe1cc32dSStefano Zampini           if (val == defval) continue;
1152fe1cc32dSStefano Zampini 
11539566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
115448a46eb9SPierre Jolivet           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
11559566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1156fe1cc32dSStefano Zampini         }
1157fe1cc32dSStefano Zampini       }
1158fe1cc32dSStefano Zampini     }
1159fe1cc32dSStefano Zampini 
11609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
11619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
11629566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
11639566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
11640588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
1165552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
1166552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
1167552f7358SJed Brown \\usetikzlibrary{arrows}\n\
11685f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
11690588280cSMatthew G. Knepley     if (size > 1) {
11709566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1171770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
117263a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
117363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1174770b213bSMatthew G Knepley       }
11759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
11760588280cSMatthew G. Knepley     }
1177b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1178b862f699SMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart)));
1179b7f6ffafSMatthew G. Knepley 
118063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
118163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
118263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
11839566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
118463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
118563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
11869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
118763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
1188b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart));
1189b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1));
1190b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.));
1191b862f699SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart));
119263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
119363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
119463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
11959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1196b7f6ffafSMatthew G. Knepley     }
11979566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1198fe1cc32dSStefano Zampini 
1199552f7358SJed Brown     /* Plot vertices */
12009566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
12019566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1202552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1203552f7358SJed Brown       PetscInt  off, dof, d;
12040588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1205552f7358SJed Brown 
1206fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
12079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
12089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
12099566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
121063a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
12110588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
12120588280cSMatthew G. Knepley         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1213c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
12140588280cSMatthew G. Knepley       }
12150588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
12169371c9d4SSatish Balay       if (dim == 3) {
12179371c9d4SSatish Balay         PetscReal tmp = tcoords[1];
12189371c9d4SSatish Balay         tcoords[1]    = tcoords[2];
12199371c9d4SSatish Balay         tcoords[2]    = -tmp;
12209371c9d4SSatish Balay       }
1221552f7358SJed Brown       for (d = 0; d < dof; ++d) {
12229566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
12239566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1224552f7358SJed Brown       }
1225b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0 % numColors];
1226b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
12270588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
12280588280cSMatthew G. Knepley         PetscInt val;
12299566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
12309371c9d4SSatish Balay         if (val >= 0) {
12319371c9d4SSatish Balay           color     = lcolors[l % numLColors];
12329371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
12339371c9d4SSatish Balay           break;
12349371c9d4SSatish Balay         }
12350588280cSMatthew G. Knepley       }
1236b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
123763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1238b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
123963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
12401baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1241552f7358SJed Brown     }
12429566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
12439566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1244b7f6ffafSMatthew G. Knepley     /* Plot edges */
1245b7f6ffafSMatthew G. Knepley     if (plotEdges) {
12469566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
12479566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1248b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1249b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1250b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1251b7f6ffafSMatthew G. Knepley 
1252b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
12539566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
125463a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
12559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
12569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
12579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
12589566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
12599566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1260b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1261b7f6ffafSMatthew G. Knepley           tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1262b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1263b7f6ffafSMatthew G. Knepley         }
1264b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
12659371c9d4SSatish Balay         if (dim == 3) {
12669371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
12679371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
12689371c9d4SSatish Balay           tcoords[2]    = -tmp;
12699371c9d4SSatish Balay         }
1270b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
12719566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
12729566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1273b7f6ffafSMatthew G. Knepley         }
1274b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1 % numColors];
1275b7f6ffafSMatthew G. Knepley         else color = colors[rank % numColors];
1276b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1277b7f6ffafSMatthew G. Knepley           PetscInt val;
1278bd3611e6SMatthew G. Knepley           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
12799371c9d4SSatish Balay           if (val >= 0) {
12809371c9d4SSatish Balay             color = lcolors[l % numLColors];
12819371c9d4SSatish Balay             break;
12829371c9d4SSatish Balay           }
1283b7f6ffafSMatthew G. Knepley         }
128463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1285b7f6ffafSMatthew G. Knepley       }
12869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
12879566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
12889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1289b7f6ffafSMatthew G. Knepley     }
1290846a3e8bSMatthew G. Knepley     /* Plot cells */
1291b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1292846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1293846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1294846a3e8bSMatthew G. Knepley 
1295fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1296846a3e8bSMatthew G. Knepley         color = colors[rank % numColors];
1297846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1298846a3e8bSMatthew G. Knepley           PetscInt val;
12999566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
13009371c9d4SSatish Balay           if (val >= 0) {
13019371c9d4SSatish Balay             color = lcolors[l % numLColors];
13029371c9d4SSatish Balay             break;
13039371c9d4SSatish Balay           }
1304846a3e8bSMatthew G. Knepley         }
13059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
130663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1307846a3e8bSMatthew G. Knepley       }
1308846a3e8bSMatthew G. Knepley     } else {
1309b7f6ffafSMatthew G. Knepley       DMPolytopeType ct;
1310846a3e8bSMatthew G. Knepley 
1311b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1312b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1313fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
13149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
1315c306944fSJed Brown         if (DMPolytopeTypeIsHybrid(ct)) {
1316b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1317b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1318b7f6ffafSMatthew G. Knepley 
13199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
13209566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1321b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1322b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1323b7f6ffafSMatthew G. Knepley 
13249566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
132563a3b9bcSJacob 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));
1326b7f6ffafSMatthew G. Knepley           }
1327b7f6ffafSMatthew G. Knepley         } else {
1328b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1329b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1330b7f6ffafSMatthew G. Knepley 
13319566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1332846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize * 2; p += 2) {
1333846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1334846a3e8bSMatthew G. Knepley 
1335b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1336846a3e8bSMatthew G. Knepley           }
13379566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1338b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1339b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v % Nv];
1340b7f6ffafSMatthew G. Knepley 
1341b7f6ffafSMatthew G. Knepley             if (v > 0) {
1342b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1343b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1344b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1345b7f6ffafSMatthew G. Knepley 
13469371c9d4SSatish Balay                 endpoints[0] = closure[v - 1];
13479371c9d4SSatish Balay                 endpoints[1] = vertex;
13489566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
134963a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
135063a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
13519566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
13521baa6e33SBarry Smith               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1353b7f6ffafSMatthew G. Knepley             }
135463a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1355b7f6ffafSMatthew G. Knepley           }
13569566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
13579566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1358846a3e8bSMatthew G. Knepley         }
1359846a3e8bSMatthew G. Knepley       }
1360b7f6ffafSMatthew G. Knepley     }
1361846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1362846a3e8bSMatthew G. Knepley       double             ccoords[3] = {0.0, 0.0, 0.0};
1363846a3e8bSMatthew G. Knepley       PetscBool          isLabeled  = PETSC_FALSE;
1364c713ec31SMatthew G. Knepley       PetscScalar       *cellCoords = NULL;
1365c713ec31SMatthew G. Knepley       const PetscScalar *array;
1366c713ec31SMatthew G. Knepley       PetscInt           numCoords, cdim, d;
1367c713ec31SMatthew G. Knepley       PetscBool          isDG;
1368846a3e8bSMatthew G. Knepley 
1369fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1370c713ec31SMatthew G. Knepley       PetscCall(DMGetCoordinateDim(dm, &cdim));
1371c713ec31SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1372c713ec31SMatthew G. Knepley       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
13739566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1374c713ec31SMatthew G. Knepley       for (p = 0; p < numCoords / cdim; ++p) {
1375c713ec31SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
1376c713ec31SMatthew G. Knepley           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1377846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1378846a3e8bSMatthew G. Knepley         }
1379846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
13809371c9d4SSatish Balay         if (cdim == 3) {
13819371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
13829371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
13839371c9d4SSatish Balay           tcoords[2]    = -tmp;
13849371c9d4SSatish Balay         }
1385ad540459SPierre Jolivet         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1386846a3e8bSMatthew G. Knepley       }
1387ad540459SPierre Jolivet       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1388c713ec31SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1389c713ec31SMatthew G. Knepley       for (d = 0; d < cdim; ++d) {
13909566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
13919566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1392846a3e8bSMatthew G. Knepley       }
1393b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth % numColors];
1394b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
1395846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1396846a3e8bSMatthew G. Knepley         PetscInt val;
13979566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
13989371c9d4SSatish Balay         if (val >= 0) {
13999371c9d4SSatish Balay           color     = lcolors[l % numLColors];
14009371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
14019371c9d4SSatish Balay           break;
14029371c9d4SSatish Balay         }
1403846a3e8bSMatthew G. Knepley       }
1404b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
140563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1406b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
140763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
14081baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1409846a3e8bSMatthew G. Knepley     }
1410b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1411b862f699SMatthew G. Knepley       int height = 0;
1412b862f699SMatthew G. Knepley 
1413b7f6ffafSMatthew G. Knepley       color = colors[depth % numColors];
14149566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
14159566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
14169566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1417b862f699SMatthew 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++));
14189566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1419552f7358SJed Brown 
1420b862f699SMatthew G. Knepley       if (depth > 2) {
1421b862f699SMatthew G. Knepley         color = colors[1 % numColors];
1422b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n"));
1423b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n"));
1424b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1425b862f699SMatthew 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++));
1426b862f699SMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1427b862f699SMatthew G. Knepley       }
1428b862f699SMatthew G. Knepley 
1429b7f6ffafSMatthew G. Knepley       color = colors[1 % numColors];
14309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
14319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
14329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1433b862f699SMatthew 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++));
14349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1435b7f6ffafSMatthew G. Knepley 
1436b7f6ffafSMatthew G. Knepley       color = colors[0 % numColors];
14379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
14389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
14399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1440b862f699SMatthew 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++));
14419566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1442b7f6ffafSMatthew G. Knepley 
1443b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1444b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1445b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1446b7f6ffafSMatthew G. Knepley 
14479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
14489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
144948a46eb9SPierre 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));
14500588280cSMatthew G. Knepley       }
14510588280cSMatthew G. Knepley     }
14529566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
14539566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
14549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
145563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
14569566063dSJacob Faibussowitsch     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
14579566063dSJacob Faibussowitsch     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
14589566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
14599566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
14609566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
14610f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
14620f7d6e4aSStefano Zampini     Vec                    cown, acown;
14630f7d6e4aSStefano Zampini     VecScatter             sct;
14640f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
14650f7d6e4aSStefano Zampini     IS                     gid, acis;
14660f7d6e4aSStefano Zampini     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
14670f7d6e4aSStefano Zampini     MPI_Group              ggroup, ngroup;
14680f7d6e4aSStefano Zampini     PetscScalar           *array, nid;
14690f7d6e4aSStefano Zampini     const PetscInt        *idxs;
14700f7d6e4aSStefano Zampini     PetscInt              *idxs2, *start, *adjacency, *work;
14710f7d6e4aSStefano Zampini     PetscInt64             lm[3], gm[3];
14720f7d6e4aSStefano Zampini     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
14730f7d6e4aSStefano Zampini     PetscMPIInt            d1, d2, rank;
14740f7d6e4aSStefano Zampini 
14759566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
14769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1477b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
14789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
14790f7d6e4aSStefano Zampini #endif
14800f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
14819566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
14829566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
14830f7d6e4aSStefano Zampini       d1 = 0;
14849566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
14850f7d6e4aSStefano Zampini       nid = d2;
14869566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
14879566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
14889566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
14890f7d6e4aSStefano Zampini     } else nid = 0.0;
14900f7d6e4aSStefano Zampini 
14910f7d6e4aSStefano Zampini     /* Get connectivity */
14929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
14939566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
14940f7d6e4aSStefano Zampini 
14950f7d6e4aSStefano Zampini     /* filter overlapped local cells */
14969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
14979566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid, &idxs));
14989566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid, &cum));
14999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &idxs2));
15000f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
15010f7d6e4aSStefano Zampini       if (idxs[c - cStart] < 0) continue;
15020f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c - cStart];
15030f7d6e4aSStefano Zampini     }
15049566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid, &idxs));
150563a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
15069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
15079566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
15080f7d6e4aSStefano Zampini 
15090f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
15109566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
15119566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
15129566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
15139566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown, &array));
15140f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
15159566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown, &array));
15169566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
15179566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
15189566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
15199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
15209566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
15219566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
15220f7d6e4aSStefano Zampini 
15230f7d6e4aSStefano Zampini     /* compute edgeCut */
15240f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
15259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &work));
15269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
15279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
15289566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
15299566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown, &array));
15300f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
15310f7d6e4aSStefano Zampini       PetscInt totl;
15320f7d6e4aSStefano Zampini 
15330f7d6e4aSStefano Zampini       totl = start[c + 1] - start[c];
15349566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
15350f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
15360f7d6e4aSStefano Zampini         if (work[i] < 0) {
15370f7d6e4aSStefano Zampini           ect += 1;
15380f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
15390f7d6e4aSStefano Zampini         }
15400f7d6e4aSStefano Zampini       }
15410f7d6e4aSStefano Zampini     }
15429566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
15439566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown, &array));
15440f7d6e4aSStefano Zampini     lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
15450f7d6e4aSStefano Zampini     lm[1] = -numVertices;
15461c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
154763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0]));
15480f7d6e4aSStefano Zampini     lm[0] = ect;                     /* edgeCut */
15490f7d6e4aSStefano Zampini     lm[1] = ectn;                    /* node-aware edgeCut */
15500f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
15511c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
155263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1553b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1554f4f49eeaSPierre Jolivet     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.));
15550f7d6e4aSStefano Zampini #else
155663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
15570f7d6e4aSStefano Zampini #endif
15589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
15599566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
15609566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
15619566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1562552f7358SJed Brown   } else {
1563412e9a14SMatthew G. Knepley     const char    *name;
1564d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1565412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1566d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1567ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
15689318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1569412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1570412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1571552f7358SJed Brown 
15729566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15739566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
15749566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
15759566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
15769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
15779566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
157863a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
157963a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
158063a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
15819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
15821c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
15832827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1584d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
15859566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
15869566063dSJacob Faibussowitsch     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1587412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1588412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1589412e9a14SMatthew G. Knepley 
15909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
15919566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1592412e9a14SMatthew G. Knepley       ict = ct0;
15939566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1594412e9a14SMatthew G. Knepley       ct0 = (DMPolytopeType)ict;
1595412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1596412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1597412e9a14SMatthew G. Knepley 
15989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1599412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1600412e9a14SMatthew G. Knepley         else ++Nc[1];
1601412e9a14SMatthew G. Knepley       }
1602ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
16039566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
16049566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
16059566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
160663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1607834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1608dd400576SPatrick Sanan           if (rank == 0) {
160963a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
161063a3b9bcSJacob Faibussowitsch             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
161163a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1612834065abSMatthew G. Knepley           }
1613cbb7f117SMark Adams         }
1614ca7bf7eeSMatthew G. Knepley       } else {
1615ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1616ca7bf7eeSMatthew G. Knepley 
16179371c9d4SSatish Balay         locMinMax[0] = Nc[0] + Nc[1];
16189371c9d4SSatish Balay         locMinMax[1] = Nc[0] + Nc[1];
16199566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
16209371c9d4SSatish Balay         locMinMax[0] = Nc[1];
16219371c9d4SSatish Balay         locMinMax[1] = Nc[1];
16229566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1623ca7bf7eeSMatthew G. Knepley         if (d == depth) {
16249371c9d4SSatish Balay           locMinMax[0] = gcNum;
16259371c9d4SSatish Balay           locMinMax[1] = gcNum;
16269566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1627ca7bf7eeSMatthew G. Knepley         }
162863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
16299566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
16309566063dSJacob Faibussowitsch         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
16319566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1632ca7bf7eeSMatthew G. Knepley       }
16339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1634552f7358SJed Brown     }
16359566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
16369318fe57SMatthew G. Knepley     {
16379318fe57SMatthew G. Knepley       const PetscReal *maxCell;
16389318fe57SMatthew G. Knepley       const PetscReal *L;
16396858538eSMatthew G. Knepley       PetscBool        localized;
16409318fe57SMatthew G. Knepley 
16414fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
16429566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
16436858538eSMatthew G. Knepley       if (L || localized) {
16446858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
16459566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
16466858538eSMatthew G. Knepley         if (L) {
16476858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
16489318fe57SMatthew G. Knepley           for (d = 0; d < dim; ++d) {
16496858538eSMatthew G. Knepley             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
16506858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
16519318fe57SMatthew G. Knepley           }
16526858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
16536858538eSMatthew G. Knepley         }
16546858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
16559566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
16569318fe57SMatthew G. Knepley       }
16579318fe57SMatthew G. Knepley     }
16589566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
16599566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1660a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1661a57dd577SMatthew G Knepley       DMLabel     label;
1662a57dd577SMatthew G Knepley       const char *name;
1663281879d4SJames Wright       PetscInt   *values;
1664a57dd577SMatthew G Knepley       PetscInt    numValues, v;
1665a57dd577SMatthew G Knepley 
16669566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
16679566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
16689566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
166963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1670281879d4SJames Wright 
1671281879d4SJames Wright       { // Extract array of DMLabel values so it can be sorted
1672281879d4SJames Wright         IS              is_values;
1673281879d4SJames Wright         const PetscInt *is_values_local = NULL;
1674281879d4SJames Wright 
1675281879d4SJames Wright         PetscCall(DMLabelGetValueIS(label, &is_values));
1676281879d4SJames Wright         PetscCall(ISGetIndices(is_values, &is_values_local));
1677281879d4SJames Wright         PetscCall(PetscMalloc1(numValues, &values));
1678281879d4SJames Wright         PetscCall(PetscArraycpy(values, is_values_local, numValues));
1679281879d4SJames Wright         PetscCall(PetscSortInt(numValues, values));
1680281879d4SJames Wright         PetscCall(ISRestoreIndices(is_values, &is_values_local));
1681281879d4SJames Wright         PetscCall(ISDestroy(&is_values));
1682281879d4SJames Wright       }
16839566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1684a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1685a57dd577SMatthew G Knepley         PetscInt size;
1686a57dd577SMatthew G Knepley 
16879566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
16889566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
168963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1690a57dd577SMatthew G Knepley       }
16919566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
16929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1693281879d4SJames Wright       PetscCall(PetscFree(values));
1694a57dd577SMatthew G Knepley     }
1695c1cad2e7SMatthew G. Knepley     {
1696c1cad2e7SMatthew G. Knepley       char    **labelNames;
1697c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1698c1cad2e7SMatthew G. Knepley       PetscBool flg;
1699c1cad2e7SMatthew G. Knepley 
17009566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
17019566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1702c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1703c1cad2e7SMatthew G. Knepley         DMLabel label;
1704c1cad2e7SMatthew G. Knepley 
17059566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1706c1cad2e7SMatthew G. Knepley         if (flg) {
17079566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
17089566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1709c1cad2e7SMatthew G. Knepley         }
17109566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1711c1cad2e7SMatthew G. Knepley       }
17129566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1713c1cad2e7SMatthew G. Knepley     }
171434aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
171534aa8a36SMatthew G. Knepley     if (dm->Nf) {
171634aa8a36SMatthew G. Knepley       PetscInt f;
171734aa8a36SMatthew G. Knepley 
171834aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
171934aa8a36SMatthew G. Knepley         const char *name;
172034aa8a36SMatthew G. Knepley 
17219566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
17229566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
17239566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
17249566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
172534aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
17269566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
17279566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
172834aa8a36SMatthew G. Knepley         } else {
17299566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
17309566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
173134aa8a36SMatthew G. Knepley         }
17329566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
173334aa8a36SMatthew G. Knepley       }
173434aa8a36SMatthew G. Knepley     }
17359566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
17368e7ff633SMatthew G. Knepley     if (cdm) {
17379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
17389f4ada15SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
17399566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
17409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
17418e7ff633SMatthew G. Knepley     }
1742552f7358SJed Brown   }
17433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1744552f7358SJed Brown }
1745552f7358SJed Brown 
1746d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1747d71ae5a4SJacob Faibussowitsch {
1748e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1749e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1750a12d352dSMatthew G. Knepley   PetscInt       cdim;
1751e5c487bfSMatthew G. Knepley 
1752e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
17539566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
17559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1756e5c487bfSMatthew G. Knepley   switch (ct) {
1757a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1758a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1759a12d352dSMatthew G. Knepley     switch (cdim) {
17609371c9d4SSatish Balay     case 1: {
1761a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1762a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1763a12d352dSMatthew G. Knepley 
17649566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
17659566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
17669566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
17679371c9d4SSatish Balay     } break;
17689371c9d4SSatish Balay     case 2: {
1769a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1770a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1771a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1772a12d352dSMatthew G. Knepley 
17739566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17749566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK));
17759566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK));
17769371c9d4SSatish Balay     } break;
1777d71ae5a4SJacob Faibussowitsch     default:
1778d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1779a12d352dSMatthew G. Knepley     }
1780a12d352dSMatthew G. Knepley     break;
1781e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
17829371c9d4SSatish Balay     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
17839566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17849566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
17859566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1786e5c487bfSMatthew G. Knepley     break;
1787e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
17889371c9d4SSatish Balay     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
17899371c9d4SSatish Balay     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
17909566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17919566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
17929566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
17939566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1794e5c487bfSMatthew G. Knepley     break;
17959f4ada15SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
17969f4ada15SMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
17979f4ada15SMatthew G. Knepley     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
17989f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17999f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
18009f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
18019f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
18029f4ada15SMatthew G. Knepley     break;
1803d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_FV_GHOST:
1804d71ae5a4SJacob Faibussowitsch     break;
1805d71ae5a4SJacob Faibussowitsch   default:
1806d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1807e5c487bfSMatthew G. Knepley   }
18083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1809e5c487bfSMatthew G. Knepley }
1810e5c487bfSMatthew G. Knepley 
1811c5aedaa3SMatthew 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[])
1812d71ae5a4SJacob Faibussowitsch {
1813e5c487bfSMatthew G. Knepley   PetscReal   centroid[2] = {0., 0.};
1814e5c487bfSMatthew G. Knepley   PetscMPIInt rank;
1815*6497c311SBarry Smith   PetscMPIInt fillColor;
1816e5c487bfSMatthew G. Knepley 
1817e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
18189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1819e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1820c5aedaa3SMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
1821c5aedaa3SMatthew G. Knepley     centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv;
1822c5aedaa3SMatthew G. Knepley     centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv;
18239371c9d4SSatish Balay   }
1824c5aedaa3SMatthew G. Knepley   for (PetscInt e = 0; e < Nv; ++e) {
1825e5c487bfSMatthew G. Knepley     refCoords[0] = refVertices[e * 2 + 0];
1826e5c487bfSMatthew G. Knepley     refCoords[1] = refVertices[e * 2 + 1];
1827c5aedaa3SMatthew G. Knepley     for (PetscInt d = 1; d <= edgeDiv; ++d) {
1828c5aedaa3SMatthew G. Knepley       refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv;
1829c5aedaa3SMatthew G. Knepley       refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv;
1830e5c487bfSMatthew G. Knepley     }
18319566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1832c5aedaa3SMatthew G. Knepley     for (PetscInt d = 0; d < edgeDiv; ++d) {
18339566063dSJacob 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));
18349566063dSJacob 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));
1835e5c487bfSMatthew G. Knepley     }
1836e5c487bfSMatthew G. Knepley   }
1837c5aedaa3SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1838c5aedaa3SMatthew G. Knepley }
1839c5aedaa3SMatthew G. Knepley 
1840c5aedaa3SMatthew G. Knepley static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1841c5aedaa3SMatthew G. Knepley {
1842c5aedaa3SMatthew G. Knepley   DMPolytopeType ct;
1843c5aedaa3SMatthew G. Knepley 
1844c5aedaa3SMatthew G. Knepley   PetscFunctionBegin;
1845c5aedaa3SMatthew G. Knepley   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1846c5aedaa3SMatthew G. Knepley   switch (ct) {
1847c5aedaa3SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE: {
1848c5aedaa3SMatthew G. Knepley     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1849c5aedaa3SMatthew G. Knepley 
1850c5aedaa3SMatthew G. Knepley     PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1851c5aedaa3SMatthew G. Knepley   } break;
1852c5aedaa3SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL: {
1853c5aedaa3SMatthew G. Knepley     PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.};
1854c5aedaa3SMatthew G. Knepley 
1855c5aedaa3SMatthew G. Knepley     PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords));
18569371c9d4SSatish Balay   } break;
1857d71ae5a4SJacob Faibussowitsch   default:
1858d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1859e5c487bfSMatthew G. Knepley   }
18603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1861e5c487bfSMatthew G. Knepley }
1862e5c487bfSMatthew G. Knepley 
1863d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1864d71ae5a4SJacob Faibussowitsch {
1865e412dcbdSMatthew G. Knepley   PetscDraw    draw;
1866e412dcbdSMatthew G. Knepley   DM           cdm;
1867e412dcbdSMatthew G. Knepley   PetscSection coordSection;
1868e412dcbdSMatthew G. Knepley   Vec          coordinates;
1869c9c77995SMatthew G. Knepley   PetscReal    xyl[3], xyr[3];
1870e5c487bfSMatthew G. Knepley   PetscReal   *refCoords, *edgeCoords;
1871c5aedaa3SMatthew G. Knepley   PetscBool    isnull, drawAffine;
1872c5aedaa3SMatthew G. Knepley   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv;
1873e412dcbdSMatthew G. Knepley 
1874e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
18759566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
187663a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1877c5aedaa3SMatthew G. Knepley   PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree));
1878c5aedaa3SMatthew G. Knepley   drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE;
1879c5aedaa3SMatthew G. Knepley   edgeDiv    = cDegree + 1;
18809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
18819566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
18829566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
18839566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
18849566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
18859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
18869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1887e412dcbdSMatthew G. Knepley 
18889566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
18899566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
18903ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
18919566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1892e412dcbdSMatthew G. Knepley 
1893c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
18949566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
18959566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1896e412dcbdSMatthew G. Knepley 
1897cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1898cf3064d3SMatthew G. Knepley     PetscScalar       *coords = NULL;
1899c9c77995SMatthew G. Knepley     const PetscScalar *coords_arr;
1900ba2698f1SMatthew G. Knepley     PetscInt           numCoords;
1901c9c77995SMatthew G. Knepley     PetscBool          isDG;
1902cf3064d3SMatthew G. Knepley 
1903c9c77995SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
19041baa6e33SBarry Smith     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
19051baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1906c9c77995SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1907cf3064d3SMatthew G. Knepley   }
19089566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
19099566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
19109566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
19119566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
19123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1913e412dcbdSMatthew G. Knepley }
1914e412dcbdSMatthew G. Knepley 
1915e44f6aebSMatthew G. Knepley static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1916e44f6aebSMatthew G. Knepley {
1917e44f6aebSMatthew G. Knepley   DM           odm = dm, rdm = dm, cdm;
1918e44f6aebSMatthew G. Knepley   PetscFE      fe;
1919e44f6aebSMatthew G. Knepley   PetscSpace   sp;
1920e44f6aebSMatthew G. Knepley   PetscClassId id;
1921e44f6aebSMatthew G. Knepley   PetscInt     degree;
1922e44f6aebSMatthew G. Knepley   PetscBool    hoView = PETSC_TRUE;
1923e44f6aebSMatthew G. Knepley 
1924e44f6aebSMatthew G. Knepley   PetscFunctionBegin;
1925e44f6aebSMatthew G. Knepley   PetscObjectOptionsBegin((PetscObject)dm);
1926e44f6aebSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
1927e44f6aebSMatthew G. Knepley   PetscOptionsEnd();
1928e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)dm));
1929e44f6aebSMatthew G. Knepley   *hdm = dm;
1930e44f6aebSMatthew G. Knepley   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
1931e44f6aebSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
1932e44f6aebSMatthew G. Knepley   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
1933e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
1934e44f6aebSMatthew G. Knepley   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
1935e44f6aebSMatthew G. Knepley   PetscCall(PetscFEGetBasisSpace(fe, &sp));
1936e44f6aebSMatthew G. Knepley   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
1937e44f6aebSMatthew G. Knepley   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
1938e44f6aebSMatthew G. Knepley     DM  cdm, rcdm;
1939e44f6aebSMatthew G. Knepley     Mat In;
1940e44f6aebSMatthew G. Knepley     Vec cl, rcl;
1941e44f6aebSMatthew G. Knepley 
1942e44f6aebSMatthew G. Knepley     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
1943c5aedaa3SMatthew G. Knepley     PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL));
1944e44f6aebSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
1945e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(odm, &cdm));
1946e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
1947e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(odm, &cl));
1948e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
1949e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoarseDM(rcdm, cdm));
1950e44f6aebSMatthew G. Knepley     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
1951e44f6aebSMatthew G. Knepley     PetscCall(MatMult(In, cl, rcl));
1952e44f6aebSMatthew G. Knepley     PetscCall(MatDestroy(&In));
1953e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
1954e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&odm));
1955e44f6aebSMatthew G. Knepley     odm = rdm;
1956e44f6aebSMatthew G. Knepley   }
1957e44f6aebSMatthew G. Knepley   *hdm = rdm;
1958e44f6aebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1959e44f6aebSMatthew G. Knepley }
1960e44f6aebSMatthew G. Knepley 
19611e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
19621e50132fSMatthew G. Knepley   #include <exodusII.h>
19636823f3c5SBlaise Bourdin   #include <petscviewerexodusii.h>
19641e50132fSMatthew G. Knepley #endif
19651e50132fSMatthew G. Knepley 
1966d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1967d71ae5a4SJacob Faibussowitsch {
19685f34f2dcSJed Brown   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1969002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
1970552f7358SJed Brown 
1971552f7358SJed Brown   PetscFunctionBegin;
1972552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1973552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
19759566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
19769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
19789566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
19799566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
19805f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1981552f7358SJed Brown   if (iascii) {
19828135c375SStefano Zampini     PetscViewerFormat format;
19839566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
19841baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
19851baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
1986c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1987c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
19889566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1989c6ccd67eSMatthew G. Knepley #else
1990c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1991552f7358SJed Brown #endif
1992e412dcbdSMatthew G. Knepley   } else if (isvtk) {
19939566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1994e412dcbdSMatthew G. Knepley   } else if (isdraw) {
1995e44f6aebSMatthew G. Knepley     DM hdm;
1996e44f6aebSMatthew G. Knepley 
1997e44f6aebSMatthew G. Knepley     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
1998e44f6aebSMatthew G. Knepley     PetscCall(DMPlexView_Draw(hdm, viewer));
1999e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&hdm));
20008135c375SStefano Zampini   } else if (isglvis) {
20019566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
20021e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
20031e50132fSMatthew G. Knepley   } else if (isexodus) {
20046823f3c5SBlaise Bourdin     /*
20056823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
20066823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
2007da81f932SPierre Jolivet       with ID 1, containing all cells.
20086823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
20096823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
20106823f3c5SBlaise Bourdin     */
20116823f3c5SBlaise Bourdin     PetscInt numCS;
20129566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
20136823f3c5SBlaise Bourdin     if (!numCS) {
20141e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
20159566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
20169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
20179566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
20186823f3c5SBlaise Bourdin     }
20199566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
20201e50132fSMatthew G. Knepley #endif
20215f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
20225f34f2dcSJed Brown   } else if (iscgns) {
20235f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
20245f34f2dcSJed Brown #endif
20251baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
2026cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
20279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
2028cb3ba0daSMatthew G. Knepley   if (flg) {
2029cb3ba0daSMatthew G. Knepley     Vec ranks;
20309566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
20319566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
20329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
2033cb3ba0daSMatthew G. Knepley   }
2034002a2709SMatthew G. Knepley   /* Optionally view a label */
20359566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
2036002a2709SMatthew G. Knepley   if (flg) {
2037002a2709SMatthew G. Knepley     DMLabel label;
2038002a2709SMatthew G. Knepley     Vec     val;
2039002a2709SMatthew G. Knepley 
20409566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
204128b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
20429566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
20439566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
20449566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
2045002a2709SMatthew G. Knepley   }
20463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2047552f7358SJed Brown }
2048552f7358SJed Brown 
20497f96f51bSksagiyam /*@
2050a1cb98faSBarry Smith   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
20517f96f51bSksagiyam 
205220f4b53cSBarry Smith   Collective
20537f96f51bSksagiyam 
20547f96f51bSksagiyam   Input Parameters:
2055a1cb98faSBarry Smith + dm     - The `DM` whose topology is to be saved
2056a1cb98faSBarry Smith - viewer - The `PetscViewer` to save it in
20577f96f51bSksagiyam 
20587f96f51bSksagiyam   Level: advanced
20597f96f51bSksagiyam 
20601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
20617f96f51bSksagiyam @*/
2062d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2063d71ae5a4SJacob Faibussowitsch {
20647f96f51bSksagiyam   PetscBool ishdf5;
20657f96f51bSksagiyam 
20667f96f51bSksagiyam   PetscFunctionBegin;
20677f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20687f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20709566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
20717f96f51bSksagiyam   if (ishdf5) {
20727f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
20737f96f51bSksagiyam     PetscViewerFormat format;
20749566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20757f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20767f96f51bSksagiyam       IS globalPointNumbering;
20777f96f51bSksagiyam 
20789566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
20799566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
20809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
208198921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
20827f96f51bSksagiyam #else
20837f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20847f96f51bSksagiyam #endif
20857f96f51bSksagiyam   }
20869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
20873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20887f96f51bSksagiyam }
20897f96f51bSksagiyam 
209077b8e257Sksagiyam /*@
2091a1cb98faSBarry Smith   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
209277b8e257Sksagiyam 
209320f4b53cSBarry Smith   Collective
209477b8e257Sksagiyam 
209577b8e257Sksagiyam   Input Parameters:
2096a1cb98faSBarry Smith + dm     - The `DM` whose coordinates are to be saved
2097a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
209877b8e257Sksagiyam 
209977b8e257Sksagiyam   Level: advanced
210077b8e257Sksagiyam 
21011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
210277b8e257Sksagiyam @*/
2103d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2104d71ae5a4SJacob Faibussowitsch {
210577b8e257Sksagiyam   PetscBool ishdf5;
210677b8e257Sksagiyam 
210777b8e257Sksagiyam   PetscFunctionBegin;
210877b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
210977b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21109566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
211277b8e257Sksagiyam   if (ishdf5) {
211377b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
211477b8e257Sksagiyam     PetscViewerFormat format;
21159566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
211677b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21179566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
2118fe28d297SMatthew Knepley     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
211977b8e257Sksagiyam #else
212077b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
212177b8e257Sksagiyam #endif
212277b8e257Sksagiyam   }
21239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
21243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
212577b8e257Sksagiyam }
212677b8e257Sksagiyam 
2127bd6565f1Sksagiyam /*@
2128a1cb98faSBarry Smith   DMPlexLabelsView - Saves `DMPLEX` labels into a file
2129bd6565f1Sksagiyam 
213020f4b53cSBarry Smith   Collective
2131bd6565f1Sksagiyam 
2132bd6565f1Sksagiyam   Input Parameters:
2133a1cb98faSBarry Smith + dm     - The `DM` whose labels are to be saved
2134a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
2135bd6565f1Sksagiyam 
2136bd6565f1Sksagiyam   Level: advanced
2137bd6565f1Sksagiyam 
21381cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2139bd6565f1Sksagiyam @*/
2140d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2141d71ae5a4SJacob Faibussowitsch {
2142bd6565f1Sksagiyam   PetscBool ishdf5;
2143bd6565f1Sksagiyam 
2144bd6565f1Sksagiyam   PetscFunctionBegin;
2145bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2146bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2149bd6565f1Sksagiyam   if (ishdf5) {
2150bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
2151bd6565f1Sksagiyam     IS                globalPointNumbering;
2152bd6565f1Sksagiyam     PetscViewerFormat format;
2153bd6565f1Sksagiyam 
21549566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2155bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21569566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
21579566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
21589566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
215998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2160bd6565f1Sksagiyam #else
2161bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2162bd6565f1Sksagiyam #endif
2163bd6565f1Sksagiyam   }
21649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
21653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2166bd6565f1Sksagiyam }
2167bd6565f1Sksagiyam 
2168021affd3Sksagiyam /*@
2169a1cb98faSBarry Smith   DMPlexSectionView - Saves a section associated with a `DMPLEX`
2170021affd3Sksagiyam 
217120f4b53cSBarry Smith   Collective
2172021affd3Sksagiyam 
2173021affd3Sksagiyam   Input Parameters:
2174a1cb98faSBarry Smith + dm        - The `DM` that contains the topology on which the section to be saved is defined
2175a1cb98faSBarry Smith . viewer    - The `PetscViewer` for saving
21760318f8a0SStefano Zampini - sectiondm - The `DM` that contains the section to be saved, can be `NULL`
2177021affd3Sksagiyam 
2178021affd3Sksagiyam   Level: advanced
2179021affd3Sksagiyam 
2180021affd3Sksagiyam   Notes:
2181420bcc1bSBarry 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.
2182021affd3Sksagiyam 
21830318f8a0SStefano 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.
2184021affd3Sksagiyam 
21851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2186021affd3Sksagiyam @*/
2187d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2188d71ae5a4SJacob Faibussowitsch {
2189021affd3Sksagiyam   PetscBool ishdf5;
2190021affd3Sksagiyam 
2191021affd3Sksagiyam   PetscFunctionBegin;
2192021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2193021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21940318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
2195021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
21969566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21979566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2198021affd3Sksagiyam   if (ishdf5) {
2199021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
22009566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2201021affd3Sksagiyam #else
2202021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2203021affd3Sksagiyam #endif
2204021affd3Sksagiyam   }
22059566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
22063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2207021affd3Sksagiyam }
2208021affd3Sksagiyam 
22093e97647fSksagiyam /*@
22103e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
22113e97647fSksagiyam 
221220f4b53cSBarry Smith   Collective
22133e97647fSksagiyam 
22143e97647fSksagiyam   Input Parameters:
2215a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2216a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
22170318f8a0SStefano Zampini . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
22183e97647fSksagiyam - vec       - The global vector to be saved
22193e97647fSksagiyam 
22203e97647fSksagiyam   Level: advanced
22213e97647fSksagiyam 
22223e97647fSksagiyam   Notes:
22230318f8a0SStefano 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.
22243e97647fSksagiyam 
222560225df5SJacob Faibussowitsch   Calling sequence:
2226a1cb98faSBarry Smith .vb
2227a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2228a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2229a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2230a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2231a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2232a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2233a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2234a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2235a1cb98faSBarry Smith        PetscSectionSetUp(section);
2236a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2237a1cb98faSBarry Smith        PetscSectionDestroy(&section);
2238a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2239a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2240a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2241a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2242a1cb98faSBarry Smith        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2243a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2244a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2245a1cb98faSBarry Smith        DMDestroy(&dm);
2246a1cb98faSBarry Smith .ve
22473e97647fSksagiyam 
22481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
22493e97647fSksagiyam @*/
2250d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2251d71ae5a4SJacob Faibussowitsch {
22523e97647fSksagiyam   PetscBool ishdf5;
22533e97647fSksagiyam 
22543e97647fSksagiyam   PetscFunctionBegin;
22553e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22563e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22570318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
22583e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
22593e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
22603e97647fSksagiyam   /* Check consistency */
22613e97647fSksagiyam   {
22623e97647fSksagiyam     PetscSection section;
22633e97647fSksagiyam     PetscBool    includesConstraints;
22643e97647fSksagiyam     PetscInt     m, m1;
22653e97647fSksagiyam 
22669566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
22679566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
22689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
22699566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
22709566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
227163a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
22723e97647fSksagiyam   }
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
22753e97647fSksagiyam   if (ishdf5) {
22763e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
22779566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
22783e97647fSksagiyam #else
22793e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
22803e97647fSksagiyam #endif
22813e97647fSksagiyam   }
22829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
22833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22843e97647fSksagiyam }
22853e97647fSksagiyam 
22863e97647fSksagiyam /*@
22873e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
22883e97647fSksagiyam 
228920f4b53cSBarry Smith   Collective
22903e97647fSksagiyam 
22913e97647fSksagiyam   Input Parameters:
2292a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2293a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
22940318f8a0SStefano Zampini . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL`
22953e97647fSksagiyam - vec       - The local vector to be saved
22963e97647fSksagiyam 
22973e97647fSksagiyam   Level: advanced
22983e97647fSksagiyam 
2299a1cb98faSBarry Smith   Note:
23000318f8a0SStefano 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.
23013e97647fSksagiyam 
230260225df5SJacob Faibussowitsch   Calling sequence:
2303a1cb98faSBarry Smith .vb
2304a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2305a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2306a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2307a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2308a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2309a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2310a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2311a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2312a1cb98faSBarry Smith        PetscSectionSetUp(section);
2313a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2314a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2315a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2316a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2317a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2318a1cb98faSBarry Smith        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2319a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2320a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2321a1cb98faSBarry Smith        DMDestroy(&dm);
2322a1cb98faSBarry Smith .ve
23233e97647fSksagiyam 
23241cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
23253e97647fSksagiyam @*/
2326d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2327d71ae5a4SJacob Faibussowitsch {
23283e97647fSksagiyam   PetscBool ishdf5;
23293e97647fSksagiyam 
23303e97647fSksagiyam   PetscFunctionBegin;
23313e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23323e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23330318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
23343e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
23353e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
23363e97647fSksagiyam   /* Check consistency */
23373e97647fSksagiyam   {
23383e97647fSksagiyam     PetscSection section;
23393e97647fSksagiyam     PetscBool    includesConstraints;
23403e97647fSksagiyam     PetscInt     m, m1;
23413e97647fSksagiyam 
23429566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
23439566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
23449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
23459566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
23469566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
234763a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
23483e97647fSksagiyam   }
23499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
23513e97647fSksagiyam   if (ishdf5) {
23523e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
23539566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
23543e97647fSksagiyam #else
23553e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23563e97647fSksagiyam #endif
23573e97647fSksagiyam   }
23589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
23593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23603e97647fSksagiyam }
23613e97647fSksagiyam 
2362d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2363d71ae5a4SJacob Faibussowitsch {
2364d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
23652c40f234SMatthew G. Knepley 
23662c40f234SMatthew G. Knepley   PetscFunctionBegin;
23672c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23682c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2370d4f5a9a0SVaclav Hapla   if (ishdf5) {
23712c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
23729c48423bSVaclav Hapla     PetscViewerFormat format;
23739566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
23749c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
23759566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2376509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
23779566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
237898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
23793ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
23802c40f234SMatthew G. Knepley #else
23812c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2382552f7358SJed Brown #endif
238398921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2384552f7358SJed Brown }
2385552f7358SJed Brown 
2386ea8e1828Sksagiyam /*@
2387a1cb98faSBarry Smith   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2388ea8e1828Sksagiyam 
238920f4b53cSBarry Smith   Collective
2390ea8e1828Sksagiyam 
2391ea8e1828Sksagiyam   Input Parameters:
2392a1cb98faSBarry Smith + dm     - The `DM` into which the topology is loaded
2393a1cb98faSBarry Smith - viewer - The `PetscViewer` for the saved topology
2394ea8e1828Sksagiyam 
23952fe279fdSBarry Smith   Output Parameter:
23962c9a7b26SBarry 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;
23972c9a7b26SBarry Smith   `NULL` if unneeded
2398dec9e869Sksagiyam 
2399ea8e1828Sksagiyam   Level: advanced
2400ea8e1828Sksagiyam 
24011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2402a1cb98faSBarry Smith           `PetscViewer`, `PetscSF`
2403ea8e1828Sksagiyam @*/
2404d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2405d71ae5a4SJacob Faibussowitsch {
2406ea8e1828Sksagiyam   PetscBool ishdf5;
2407ea8e1828Sksagiyam 
2408ea8e1828Sksagiyam   PetscFunctionBegin;
2409ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2410ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24114f572ea9SToby Isaac   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
24129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2414ea8e1828Sksagiyam   if (ishdf5) {
2415ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2416ea8e1828Sksagiyam     PetscViewerFormat format;
24179566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2418ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24199566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
242098921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2421ea8e1828Sksagiyam #else
2422ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2423ea8e1828Sksagiyam #endif
2424ea8e1828Sksagiyam   }
24259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
24263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2427ea8e1828Sksagiyam }
2428ea8e1828Sksagiyam 
24293e701f1cSksagiyam /*@
2430a1cb98faSBarry Smith   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
24313e701f1cSksagiyam 
243220f4b53cSBarry Smith   Collective
24333e701f1cSksagiyam 
24343e701f1cSksagiyam   Input Parameters:
2435a1cb98faSBarry Smith + dm                   - The `DM` into which the coordinates are loaded
2436a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved coordinates
2437a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
24383e701f1cSksagiyam 
24393e701f1cSksagiyam   Level: advanced
24403e701f1cSksagiyam 
24411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2442a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
24433e701f1cSksagiyam @*/
2444d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2445d71ae5a4SJacob Faibussowitsch {
24463e701f1cSksagiyam   PetscBool ishdf5;
24473e701f1cSksagiyam 
24483e701f1cSksagiyam   PetscFunctionBegin;
24493e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24503e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2451c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
24529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24539566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
24543e701f1cSksagiyam   if (ishdf5) {
24553e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
24563e701f1cSksagiyam     PetscViewerFormat format;
24579566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
24583e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24599566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
246098921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
24613e701f1cSksagiyam #else
24623e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24633e701f1cSksagiyam #endif
24643e701f1cSksagiyam   }
24659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
24663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24673e701f1cSksagiyam }
24683e701f1cSksagiyam 
2469b08ad5deSksagiyam /*@
2470a1cb98faSBarry Smith   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2471b08ad5deSksagiyam 
247220f4b53cSBarry Smith   Collective
2473b08ad5deSksagiyam 
2474b08ad5deSksagiyam   Input Parameters:
2475a1cb98faSBarry Smith + dm                   - The `DM` into which the labels are loaded
2476a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved labels
247720f4b53cSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2478b08ad5deSksagiyam 
2479b08ad5deSksagiyam   Level: advanced
2480b08ad5deSksagiyam 
2481a1cb98faSBarry Smith   Note:
2482dc9a610eSPierre Jolivet   The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs.
2483e6368b79SVaclav Hapla 
24841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2485a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
2486b08ad5deSksagiyam @*/
2487d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2488d71ae5a4SJacob Faibussowitsch {
2489b08ad5deSksagiyam   PetscBool ishdf5;
2490b08ad5deSksagiyam 
2491b08ad5deSksagiyam   PetscFunctionBegin;
2492b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2493b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2494e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
24959566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24969566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2497b08ad5deSksagiyam   if (ishdf5) {
2498b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2499b08ad5deSksagiyam     PetscViewerFormat format;
2500b08ad5deSksagiyam 
25019566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2502b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
25039566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
250498921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2505b08ad5deSksagiyam #else
2506b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2507b08ad5deSksagiyam #endif
2508b08ad5deSksagiyam   }
25099566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
25103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2511b08ad5deSksagiyam }
2512b08ad5deSksagiyam 
2513f84dd6b4Sksagiyam /*@
2514a1cb98faSBarry Smith   DMPlexSectionLoad - Loads section into a `DMPLEX`
2515f84dd6b4Sksagiyam 
251620f4b53cSBarry Smith   Collective
2517f84dd6b4Sksagiyam 
2518f84dd6b4Sksagiyam   Input Parameters:
2519a1cb98faSBarry Smith + dm                   - The `DM` that represents the topology
2520a1cb98faSBarry Smith . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
25210318f8a0SStefano Zampini . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL`
2522a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2523f84dd6b4Sksagiyam 
2524a4e35b19SJacob Faibussowitsch   Output Parameters:
252520f4b53cSBarry 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)
252620f4b53cSBarry 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)
2527f84dd6b4Sksagiyam 
2528f84dd6b4Sksagiyam   Level: advanced
2529f84dd6b4Sksagiyam 
2530f84dd6b4Sksagiyam   Notes:
253120f4b53cSBarry 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.
2532f84dd6b4Sksagiyam 
25330318f8a0SStefano 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.
2534f84dd6b4Sksagiyam 
253520f4b53cSBarry 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.
2536f84dd6b4Sksagiyam 
2537f84dd6b4Sksagiyam   Example using 2 processes:
2538a1cb98faSBarry Smith .vb
2539a1cb98faSBarry Smith   NX (number of points on dm): 4
2540a1cb98faSBarry Smith   sectionA                   : the on-disk section
2541a1cb98faSBarry Smith   vecA                       : a vector associated with sectionA
2542a1cb98faSBarry Smith   sectionB                   : sectiondm's local section constructed in this function
2543a1cb98faSBarry Smith   vecB (local)               : a vector associated with sectiondm's local section
2544a1cb98faSBarry Smith   vecB (global)              : a vector associated with sectiondm's global section
2545f84dd6b4Sksagiyam 
2546a1cb98faSBarry Smith                                      rank 0    rank 1
2547a1cb98faSBarry Smith   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2548a1cb98faSBarry Smith   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2549a1cb98faSBarry Smith   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2550a1cb98faSBarry Smith   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2551a1cb98faSBarry Smith   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2552a1cb98faSBarry Smith   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2553a1cb98faSBarry Smith   sectionB->atlasDof             :     1 0 1 | 1 3
2554a1cb98faSBarry Smith   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2555a1cb98faSBarry Smith   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2556a1cb98faSBarry Smith   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2557a1cb98faSBarry Smith .ve
2558a1cb98faSBarry Smith   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2559a1cb98faSBarry Smith 
25601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2561f84dd6b4Sksagiyam @*/
2562d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2563d71ae5a4SJacob Faibussowitsch {
2564f84dd6b4Sksagiyam   PetscBool ishdf5;
2565f84dd6b4Sksagiyam 
2566f84dd6b4Sksagiyam   PetscFunctionBegin;
2567f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2568f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
25690318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
2570f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2571f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
25724f572ea9SToby Isaac   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
25734f572ea9SToby Isaac   if (localDofSF) PetscAssertPointer(localDofSF, 6);
25749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25759566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2576f84dd6b4Sksagiyam   if (ishdf5) {
2577f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
25789566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2579f84dd6b4Sksagiyam #else
2580f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2581f84dd6b4Sksagiyam #endif
2582f84dd6b4Sksagiyam   }
25839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
25843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2585f84dd6b4Sksagiyam }
2586f84dd6b4Sksagiyam 
25878be3dfe1Sksagiyam /*@
25888be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
25898be3dfe1Sksagiyam 
259020f4b53cSBarry Smith   Collective
25918be3dfe1Sksagiyam 
25928be3dfe1Sksagiyam   Input Parameters:
2593a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2594a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
25950318f8a0SStefano Zampini . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL`
2596a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
25978be3dfe1Sksagiyam - vec       - The global vector to set values of
25988be3dfe1Sksagiyam 
25998be3dfe1Sksagiyam   Level: advanced
26008be3dfe1Sksagiyam 
26018be3dfe1Sksagiyam   Notes:
26020318f8a0SStefano 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.
26038be3dfe1Sksagiyam 
260460225df5SJacob Faibussowitsch   Calling sequence:
2605a1cb98faSBarry Smith .vb
2606a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2607a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2608a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2609a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2610a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2611a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2612a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2613a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2614a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2615a1cb98faSBarry Smith        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2616a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2617a1cb98faSBarry Smith        PetscSFDestroy(&gsf);
2618a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2619a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2620a1cb98faSBarry Smith        DMDestroy(&dm);
2621a1cb98faSBarry Smith .ve
26228be3dfe1Sksagiyam 
26231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2624a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
26258be3dfe1Sksagiyam @*/
2626d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2627d71ae5a4SJacob Faibussowitsch {
26288be3dfe1Sksagiyam   PetscBool ishdf5;
26298be3dfe1Sksagiyam 
26308be3dfe1Sksagiyam   PetscFunctionBegin;
26318be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26328be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
26330318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
26348be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
26358be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
26368be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
26378be3dfe1Sksagiyam   /* Check consistency */
26388be3dfe1Sksagiyam   {
26398be3dfe1Sksagiyam     PetscSection section;
26408be3dfe1Sksagiyam     PetscBool    includesConstraints;
26418be3dfe1Sksagiyam     PetscInt     m, m1;
26428be3dfe1Sksagiyam 
26439566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
26449566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
26459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
26469566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
26479566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
264863a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
26498be3dfe1Sksagiyam   }
26509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
26519566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
26528be3dfe1Sksagiyam   if (ishdf5) {
26538be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
26549566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
26558be3dfe1Sksagiyam #else
26568be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
26578be3dfe1Sksagiyam #endif
26588be3dfe1Sksagiyam   }
26599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
26603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26618be3dfe1Sksagiyam }
26628be3dfe1Sksagiyam 
26638be3dfe1Sksagiyam /*@
26648be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
26658be3dfe1Sksagiyam 
266620f4b53cSBarry Smith   Collective
26678be3dfe1Sksagiyam 
26688be3dfe1Sksagiyam   Input Parameters:
2669a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2670a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
26710318f8a0SStefano Zampini . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL`
2672a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
26738be3dfe1Sksagiyam - vec       - The local vector to set values of
26748be3dfe1Sksagiyam 
26758be3dfe1Sksagiyam   Level: advanced
26768be3dfe1Sksagiyam 
26778be3dfe1Sksagiyam   Notes:
26780318f8a0SStefano 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.
26798be3dfe1Sksagiyam 
268060225df5SJacob Faibussowitsch   Calling sequence:
2681a1cb98faSBarry Smith .vb
2682a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2683a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2684a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2685a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2686a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2687a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2688a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2689a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2690a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2691a1cb98faSBarry Smith        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2692a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2693a1cb98faSBarry Smith        PetscSFDestroy(&lsf);
2694a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2695a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2696a1cb98faSBarry Smith        DMDestroy(&dm);
2697a1cb98faSBarry Smith .ve
26988be3dfe1Sksagiyam 
26991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2700a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
27018be3dfe1Sksagiyam @*/
2702d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2703d71ae5a4SJacob Faibussowitsch {
27048be3dfe1Sksagiyam   PetscBool ishdf5;
27058be3dfe1Sksagiyam 
27068be3dfe1Sksagiyam   PetscFunctionBegin;
27078be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
27088be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
27090318f8a0SStefano Zampini   if (!sectiondm) sectiondm = dm;
27108be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
27118be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
27128be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
27138be3dfe1Sksagiyam   /* Check consistency */
27148be3dfe1Sksagiyam   {
27158be3dfe1Sksagiyam     PetscSection section;
27168be3dfe1Sksagiyam     PetscBool    includesConstraints;
27178be3dfe1Sksagiyam     PetscInt     m, m1;
27188be3dfe1Sksagiyam 
27199566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
27209566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
27219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
27229566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
27239566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
272463a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
27258be3dfe1Sksagiyam   }
27269566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
27279566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
27288be3dfe1Sksagiyam   if (ishdf5) {
27298be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
27309566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
27318be3dfe1Sksagiyam #else
27328be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
27338be3dfe1Sksagiyam #endif
27348be3dfe1Sksagiyam   }
27359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
27363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27378be3dfe1Sksagiyam }
27388be3dfe1Sksagiyam 
2739d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2740d71ae5a4SJacob Faibussowitsch {
2741552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2742552f7358SJed Brown 
2743552f7358SJed Brown   PetscFunctionBegin;
27449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
27459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
27469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
27479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
27486c51210dSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
27492e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
27502e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
27512e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
27522e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
27536bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
27546bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2755adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL));
2756adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL));
2757adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL));
2758adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL));
2759c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2760c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2761d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2762d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
27635f06a3ddSJed Brown   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
27643ba16761SJacob Faibussowitsch   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
27659566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
27669566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
27679566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
27689566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
27699566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
27709566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
277121027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
27729f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
27739566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
27749566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
27759566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
27761d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
27779566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
27789566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
27799566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
27809566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
27819566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
27821fca310dSJames Wright   if (mesh->periodic.face_sfs) {
27831fca310dSJames Wright     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i]));
27841fca310dSJames Wright     PetscCall(PetscFree(mesh->periodic.face_sfs));
27851fca310dSJames Wright   }
27866725e60dSJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2787b83f62b0SJames Wright   if (mesh->periodic.periodic_points) {
2788b83f62b0SJames Wright     for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i]));
2789b83f62b0SJames Wright     PetscCall(PetscFree(mesh->periodic.periodic_points));
2790b83f62b0SJames Wright   }
27911fca310dSJames Wright   if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform));
27929566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
27939566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
27949566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
27959566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
27969566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
27979566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
27989566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
27999566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
28009566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
28019566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
28029566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2803c29ce622SStefano Zampini   if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm));
2804552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
28059566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
28063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2807552f7358SJed Brown }
2808552f7358SJed Brown 
2809d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2810d71ae5a4SJacob Faibussowitsch {
2811d02c7345SMatthew G. Knepley   PetscSection           sectionGlobal, sectionLocal;
2812acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
28139fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2814837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2815b412c318SBarry Smith   MatType                mtype;
28161428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2817552f7358SJed Brown 
2818552f7358SJed Brown   PetscFunctionBegin;
28199566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2820b412c318SBarry Smith   mtype = dm->mattype;
2821d02c7345SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &sectionLocal));
28229566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
28239566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
28249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
28259fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
28269566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
28279566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
28289566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
28299566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
28309566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2831acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
28329566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
28339566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
28349566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
28359566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
28369566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
28379566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
28389566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
28399566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2840552f7358SJed Brown   if (!isShell) {
28411c6742e7SMatthew G. Knepley     // There are three states with pblocks, since block starts can have no dofs:
28421c6742e7SMatthew G. Knepley     // UNKNOWN) New Block:   An open block has been signalled by pblocks[p] == 1
28431c6742e7SMatthew G. Knepley     // TRUE)    Block Start: The first entry in a block has been added
28441c6742e7SMatthew G. Knepley     // FALSE)   Block Add:   An additional block entry has been added, since pblocks[p] == 0
28451c6742e7SMatthew G. Knepley     PetscBT         blst;
28461c6742e7SMatthew G. Knepley     PetscBool3      bstate     = PETSC_BOOL3_UNKNOWN;
2847837628f4SStefano Zampini     PetscBool       fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
28481c6742e7SMatthew G. Knepley     const PetscInt *perm       = NULL;
28499fca9976SJed Brown     PetscInt       *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
28501c6742e7SMatthew G. Knepley     PetscInt        pStart, pEnd, dof, cdof, num_fields;
2851552f7358SJed Brown 
28529566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
28531c6742e7SMatthew G. Knepley     PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst));
28541c6742e7SMatthew G. Knepley     if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm));
28559fca9976SJed Brown 
28569fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
28579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2858863027abSJed Brown     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
28591c6742e7SMatthew G. Knepley     // We need to process in the permuted order to get block sizes right
28601c6742e7SMatthew G. Knepley     for (PetscInt point = pStart; point < pEnd; ++point) {
28611c6742e7SMatthew G. Knepley       const PetscInt p = perm ? perm[point] : point;
28621c6742e7SMatthew G. Knepley 
2863863027abSJed Brown       switch (dm->blocking_type) {
28640e762ea3SJed Brown       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
28659fca9976SJed Brown         PetscInt bdof, offset;
2866a9d99c84SMatthew G. Knepley 
28679566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
28689fca9976SJed Brown         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
28699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
28701c6742e7SMatthew G. Knepley         if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN;
287132b27637SMatthew G. Knepley         if (dof > 0) {
28721c6742e7SMatthew G. Knepley           // State change
28731c6742e7SMatthew G. Knepley           if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE;
28741c6742e7SMatthew G. Knepley           else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE;
28751c6742e7SMatthew G. Knepley 
2876d02c7345SMatthew G. Knepley           for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof;
2877d02c7345SMatthew G. Knepley           // Signal block concatenation
28781c6742e7SMatthew G. Knepley           if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof);
287932b27637SMatthew G. Knepley         }
28801d17a0a3SMatthew G. Knepley         dof  = dof < 0 ? -(dof + 1) : dof;
28811d17a0a3SMatthew G. Knepley         bdof = cdof && (dof - cdof) ? 1 : dof;
28821d17a0a3SMatthew G. Knepley         if (dof) {
28839371c9d4SSatish Balay           if (bs < 0) {
28849371c9d4SSatish Balay             bs = bdof;
28859371c9d4SSatish Balay           } else if (bs != bdof) {
28869371c9d4SSatish Balay             bs = 1;
28879371c9d4SSatish Balay           }
2888552f7358SJed Brown         }
2889863027abSJed Brown       } break;
2890863027abSJed Brown       case DM_BLOCKING_FIELD_NODE: {
2891863027abSJed Brown         for (PetscInt field = 0; field < num_fields; field++) {
2892863027abSJed Brown           PetscInt num_comp, bdof, offset;
2893863027abSJed Brown           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2894863027abSJed Brown           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2895863027abSJed Brown           if (dof < 0) continue;
2896863027abSJed Brown           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2897863027abSJed Brown           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2898863027abSJed 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);
2899863027abSJed Brown           PetscInt num_nodes = dof / num_comp;
2900863027abSJed Brown           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2901863027abSJed Brown           // Handle possibly constant block size (unlikely)
2902863027abSJed Brown           bdof = cdof && (dof - cdof) ? 1 : dof;
2903863027abSJed Brown           if (dof) {
2904863027abSJed Brown             if (bs < 0) {
2905863027abSJed Brown               bs = bdof;
2906863027abSJed Brown             } else if (bs != bdof) {
2907863027abSJed Brown               bs = 1;
2908863027abSJed Brown             }
2909863027abSJed Brown           }
2910863027abSJed Brown         }
2911863027abSJed Brown       } break;
2912863027abSJed Brown       }
29132a28c762SMatthew G Knepley     }
29141c6742e7SMatthew G. Knepley     if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm));
29152a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2916e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2917e432b41dSStefano Zampini     bsLocal[1] = bs;
29189566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2919e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2920e432b41dSStefano Zampini     else bs = bsMinMax[0];
29216fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
29229566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
29230682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
29249566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
29259566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
29260682b8bbSJed Brown     } else {
29279566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
29289566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
29299566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2930552f7358SJed Brown     }
293132b27637SMatthew G. Knepley     if (pblocks) { // Consolidate blocks
29329fca9976SJed Brown       PetscInt nblocks = 0;
293332b27637SMatthew G. Knepley       pblocks[0]       = PetscAbs(pblocks[0]);
29349fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
29359fca9976SJed Brown         if (pblocks[i] == 0) continue;
2936d02c7345SMatthew G. Knepley         // Negative block size indicates the blocks should be concatenated
2937d02c7345SMatthew G. Knepley         if (pblocks[i] < 0) {
2938d02c7345SMatthew G. Knepley           pblocks[i] = -pblocks[i];
2939d02c7345SMatthew G. Knepley           pblocks[nblocks - 1] += pblocks[i];
2940d02c7345SMatthew G. Knepley         } else {
29419fca9976SJed Brown           pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2942d02c7345SMatthew G. Knepley         }
29431c6742e7SMatthew G. Knepley         for (PetscInt j = 1; j < pblocks[i]; j++)
29441c6742e7SMatthew 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);
29459fca9976SJed Brown       }
29469fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
29479fca9976SJed Brown     }
29489fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2949aa0f6e3cSJed Brown   }
29509566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
29513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2952552f7358SJed Brown }
2953552f7358SJed Brown 
29547cd05799SMatthew G. Knepley /*@
2955a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2956be36d101SStefano Zampini 
2957a1cb98faSBarry Smith   Not Collective
2958be36d101SStefano Zampini 
2959be36d101SStefano Zampini   Input Parameter:
296060225df5SJacob Faibussowitsch . dm - The `DMPLEX`
2961be36d101SStefano Zampini 
29622fe279fdSBarry Smith   Output Parameter:
2963be36d101SStefano Zampini . subsection - The subdomain section
2964be36d101SStefano Zampini 
2965be36d101SStefano Zampini   Level: developer
2966be36d101SStefano Zampini 
29671cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
29687cd05799SMatthew G. Knepley @*/
2969d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2970d71ae5a4SJacob Faibussowitsch {
2971be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
2972be36d101SStefano Zampini 
2973be36d101SStefano Zampini   PetscFunctionBegin;
2974be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2975be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2976be36d101SStefano Zampini     PetscSection section;
2977be36d101SStefano Zampini     PetscSF      sf;
2978be36d101SStefano Zampini 
29799566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
29809566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
2981eb9d3e4dSMatthew G. Knepley     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
29829566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2983be36d101SStefano Zampini   }
2984be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
29853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2986be36d101SStefano Zampini }
2987be36d101SStefano Zampini 
2988552f7358SJed Brown /*@
298920f4b53cSBarry Smith   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
2990552f7358SJed Brown 
2991a1cb98faSBarry Smith   Not Collective
2992552f7358SJed Brown 
2993552f7358SJed Brown   Input Parameter:
299460225df5SJacob Faibussowitsch . dm - The `DMPLEX`
2995552f7358SJed Brown 
2996552f7358SJed Brown   Output Parameters:
2997552f7358SJed Brown + pStart - The first mesh point
2998552f7358SJed Brown - pEnd   - The upper bound for mesh points
2999552f7358SJed Brown 
3000552f7358SJed Brown   Level: beginner
3001552f7358SJed Brown 
30021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
3003552f7358SJed Brown @*/
3004d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
3005d71ae5a4SJacob Faibussowitsch {
3006552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3007552f7358SJed Brown 
3008552f7358SJed Brown   PetscFunctionBegin;
3009552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30109f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
30119f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
30123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3013552f7358SJed Brown }
3014552f7358SJed Brown 
3015552f7358SJed Brown /*@
301620f4b53cSBarry Smith   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
3017552f7358SJed Brown 
3018a1cb98faSBarry Smith   Not Collective
3019552f7358SJed Brown 
3020552f7358SJed Brown   Input Parameters:
302160225df5SJacob Faibussowitsch + dm     - The `DMPLEX`
3022552f7358SJed Brown . pStart - The first mesh point
3023552f7358SJed Brown - pEnd   - The upper bound for mesh points
3024552f7358SJed Brown 
3025552f7358SJed Brown   Level: beginner
3026552f7358SJed Brown 
30271cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
3028552f7358SJed Brown @*/
3029d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
3030d71ae5a4SJacob Faibussowitsch {
3031552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3032552f7358SJed Brown 
3033552f7358SJed Brown   PetscFunctionBegin;
3034552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30359566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
30369566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
303721027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
30383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3039552f7358SJed Brown }
3040552f7358SJed Brown 
3041552f7358SJed Brown /*@
3042eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
3043552f7358SJed Brown 
3044a1cb98faSBarry Smith   Not Collective
3045552f7358SJed Brown 
3046552f7358SJed Brown   Input Parameters:
304760225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3048a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3049552f7358SJed Brown 
3050552f7358SJed Brown   Output Parameter:
305120f4b53cSBarry Smith . size - The cone size for point `p`
3052552f7358SJed Brown 
3053552f7358SJed Brown   Level: beginner
3054552f7358SJed Brown 
30551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3056552f7358SJed Brown @*/
3057d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
3058d71ae5a4SJacob Faibussowitsch {
3059552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3060552f7358SJed Brown 
3061552f7358SJed Brown   PetscFunctionBegin;
3062552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30634f572ea9SToby Isaac   PetscAssertPointer(size, 3);
30649f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
30659f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
30663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3067552f7358SJed Brown }
3068552f7358SJed Brown 
3069552f7358SJed Brown /*@
3070eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
3071552f7358SJed Brown 
3072a1cb98faSBarry Smith   Not Collective
3073552f7358SJed Brown 
3074552f7358SJed Brown   Input Parameters:
307560225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3076a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
307720f4b53cSBarry Smith - size - The cone size for point `p`
3078552f7358SJed Brown 
3079552f7358SJed Brown   Level: beginner
3080552f7358SJed Brown 
3081a1cb98faSBarry Smith   Note:
3082a1cb98faSBarry Smith   This should be called after `DMPlexSetChart()`.
3083a1cb98faSBarry Smith 
30842c9a7b26SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
3085552f7358SJed Brown @*/
3086d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
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   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
30939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
30943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3095552f7358SJed Brown }
3096552f7358SJed Brown 
3097552f7358SJed Brown /*@C
3098eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
3099552f7358SJed Brown 
3100a1cb98faSBarry Smith   Not Collective
3101552f7358SJed Brown 
3102552f7358SJed Brown   Input Parameters:
3103a1cb98faSBarry Smith + dm - The `DMPLEX`
3104a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3105552f7358SJed Brown 
3106552f7358SJed Brown   Output Parameter:
31072c9a7b26SBarry Smith . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()`
3108552f7358SJed Brown 
3109552f7358SJed Brown   Level: beginner
3110552f7358SJed Brown 
311160225df5SJacob Faibussowitsch   Fortran Notes:
31122c9a7b26SBarry Smith   `cone` must be declared with
31132c9a7b26SBarry Smith .vb
31142c9a7b26SBarry Smith   PetscInt, pointer :: cone(:)
31152c9a7b26SBarry Smith .ve
31162c9a7b26SBarry Smith 
31172c9a7b26SBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the array.
3118a1cb98faSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
31193813dfbdSMatthew G Knepley 
31201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3121552f7358SJed Brown @*/
3122d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3123d71ae5a4SJacob Faibussowitsch {
3124552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3125552f7358SJed Brown   PetscInt off;
3126552f7358SJed Brown 
3127552f7358SJed Brown   PetscFunctionBegin;
3128552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31294f572ea9SToby Isaac   PetscAssertPointer(cone, 3);
31309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
31318e3a54c0SPierre Jolivet   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
31323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3133552f7358SJed Brown }
3134552f7358SJed Brown 
3135cc4c1da9SBarry Smith /*@
31360ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
31370ce7577fSVaclav Hapla 
3138a1cb98faSBarry Smith   Not Collective
31390ce7577fSVaclav Hapla 
31400ce7577fSVaclav Hapla   Input Parameters:
3141a1cb98faSBarry Smith + dm - The `DMPLEX`
3142a1cb98faSBarry Smith - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
31430ce7577fSVaclav Hapla 
3144d8d19677SJose E. Roman   Output Parameters:
314520f4b53cSBarry Smith + pConesSection - `PetscSection` describing the layout of `pCones`
31462c9a7b26SBarry Smith - pCones        - An `IS` containing the points which are on the in-edges for the point set `p`
31470ce7577fSVaclav Hapla 
31480ce7577fSVaclav Hapla   Level: intermediate
31490ce7577fSVaclav Hapla 
31501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
31510ce7577fSVaclav Hapla @*/
3152d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
3153d71ae5a4SJacob Faibussowitsch {
31540ce7577fSVaclav Hapla   PetscSection cs, newcs;
31550ce7577fSVaclav Hapla   PetscInt    *cones;
31560ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
31570ce7577fSVaclav Hapla   PetscInt     n;
31580ce7577fSVaclav Hapla 
31590ce7577fSVaclav Hapla   PetscFunctionBegin;
31609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
31619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
31629566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
31630ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
31640ce7577fSVaclav Hapla   if (pCones) {
31659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
31669566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
31670ce7577fSVaclav Hapla   }
31683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31690ce7577fSVaclav Hapla }
31700ce7577fSVaclav Hapla 
3171af9eab45SVaclav Hapla /*@
3172af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
3173d4636a37SVaclav Hapla 
3174a1cb98faSBarry Smith   Not Collective
3175d4636a37SVaclav Hapla 
3176d4636a37SVaclav Hapla   Input Parameters:
3177a1cb98faSBarry Smith + dm     - The `DMPLEX`
3178a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3179d4636a37SVaclav Hapla 
3180d4636a37SVaclav Hapla   Output Parameter:
31812c9a7b26SBarry Smith . expandedPoints - An `IS` containing the of vertices recursively expanded from input points
3182d4636a37SVaclav Hapla 
3183d4636a37SVaclav Hapla   Level: advanced
3184d4636a37SVaclav Hapla 
3185af9eab45SVaclav Hapla   Notes:
318620f4b53cSBarry Smith   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
3187af9eab45SVaclav Hapla 
3188a1cb98faSBarry Smith   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
3189a1cb98faSBarry Smith 
31901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3191a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`
3192d4636a37SVaclav Hapla @*/
3193d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3194d71ae5a4SJacob Faibussowitsch {
3195af9eab45SVaclav Hapla   IS      *expandedPointsAll;
3196af9eab45SVaclav Hapla   PetscInt depth;
3197d4636a37SVaclav Hapla 
3198d4636a37SVaclav Hapla   PetscFunctionBegin;
3199af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3200af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
32014f572ea9SToby Isaac   PetscAssertPointer(expandedPoints, 3);
32029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3203af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
32049566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
32059566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
32063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3207af9eab45SVaclav Hapla }
3208af9eab45SVaclav Hapla 
3209af9eab45SVaclav Hapla /*@
32102c9a7b26SBarry Smith   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices
32112c9a7b26SBarry Smith   (DAG points of depth 0, i.e., without cones).
3212af9eab45SVaclav Hapla 
3213a1cb98faSBarry Smith   Not Collective
3214af9eab45SVaclav Hapla 
3215af9eab45SVaclav Hapla   Input Parameters:
3216a1cb98faSBarry Smith + dm     - The `DMPLEX`
3217a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3218af9eab45SVaclav Hapla 
3219d8d19677SJose E. Roman   Output Parameters:
3220a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3221af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
3222af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3223af9eab45SVaclav Hapla 
3224af9eab45SVaclav Hapla   Level: advanced
3225af9eab45SVaclav Hapla 
3226af9eab45SVaclav Hapla   Notes:
3227a1cb98faSBarry Smith   Like `DMPlexGetConeTuple()` but recursive.
3228af9eab45SVaclav Hapla 
3229a4e35b19SJacob 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.
3230af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
3231af9eab45SVaclav Hapla 
3232a4e35b19SJacob 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\:
3233a4e35b19SJacob Faibussowitsch   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3234a4e35b19SJacob Faibussowitsch   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
3235af9eab45SVaclav Hapla 
32361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3237a1cb98faSBarry Smith           `DMPlexGetDepth()`, `PetscSection`, `IS`
3238af9eab45SVaclav Hapla @*/
3239d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3240d71ae5a4SJacob Faibussowitsch {
3241af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
3242af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
3243af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3244af9eab45SVaclav Hapla   IS             *expandedPoints_;
3245af9eab45SVaclav Hapla   PetscSection   *sections_;
3246af9eab45SVaclav Hapla 
3247af9eab45SVaclav Hapla   PetscFunctionBegin;
3248af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3249af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
32504f572ea9SToby Isaac   if (depth) PetscAssertPointer(depth, 3);
32514f572ea9SToby Isaac   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
32524f572ea9SToby Isaac   if (sections) PetscAssertPointer(sections, 5);
32539566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
32549566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
32559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
32569566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
32579566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
3258af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3259af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
32609566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
32619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3262af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
32639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3264af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
32659566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
32669566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3267af9eab45SVaclav Hapla       } else {
32689566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3269af9eab45SVaclav Hapla       }
3270af9eab45SVaclav Hapla     }
32719566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
32729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
32739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
3274af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
32759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
32769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3277af9eab45SVaclav Hapla       if (cn > 1) {
32789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
32799566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3280af9eab45SVaclav Hapla       } else {
3281af9eab45SVaclav Hapla         newarr[co] = arr[i];
3282af9eab45SVaclav Hapla       }
3283af9eab45SVaclav Hapla     }
32849566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3285af9eab45SVaclav Hapla     arr = newarr;
3286af9eab45SVaclav Hapla     n   = newn;
3287af9eab45SVaclav Hapla   }
32889566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
3289af9eab45SVaclav Hapla   *depth = depth_;
3290af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
3291af9eab45SVaclav Hapla   else {
32929566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
32939566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
3294af9eab45SVaclav Hapla   }
3295af9eab45SVaclav Hapla   if (sections) *sections = sections_;
3296af9eab45SVaclav Hapla   else {
32979566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
32989566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
3299af9eab45SVaclav Hapla   }
33003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3301af9eab45SVaclav Hapla }
3302af9eab45SVaclav Hapla 
3303af9eab45SVaclav Hapla /*@
3304a1cb98faSBarry Smith   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3305af9eab45SVaclav Hapla 
3306a1cb98faSBarry Smith   Not Collective
3307af9eab45SVaclav Hapla 
3308af9eab45SVaclav Hapla   Input Parameters:
3309a1cb98faSBarry Smith + dm     - The `DMPLEX`
3310a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3311af9eab45SVaclav Hapla 
3312d8d19677SJose E. Roman   Output Parameters:
3313a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3314af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3315af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3316af9eab45SVaclav Hapla 
3317af9eab45SVaclav Hapla   Level: advanced
3318af9eab45SVaclav Hapla 
3319a1cb98faSBarry Smith   Note:
3320a1cb98faSBarry Smith   See `DMPlexGetConeRecursive()`
3321af9eab45SVaclav Hapla 
33221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3323a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`, `PetscSection`
3324af9eab45SVaclav Hapla @*/
3325d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3326d71ae5a4SJacob Faibussowitsch {
3327af9eab45SVaclav Hapla   PetscInt d, depth_;
3328af9eab45SVaclav Hapla 
3329af9eab45SVaclav Hapla   PetscFunctionBegin;
33309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
33311dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3332af9eab45SVaclav Hapla   if (depth) *depth = 0;
3333af9eab45SVaclav Hapla   if (expandedPoints) {
33349566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
33359566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3336af9eab45SVaclav Hapla   }
3337af9eab45SVaclav Hapla   if (sections) {
33389566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
33399566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3340af9eab45SVaclav Hapla   }
33413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3342d4636a37SVaclav Hapla }
3343d4636a37SVaclav Hapla 
3344552f7358SJed Brown /*@
334592371b87SBarry 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
3346552f7358SJed Brown 
3347a1cb98faSBarry Smith   Not Collective
3348552f7358SJed Brown 
3349552f7358SJed Brown   Input Parameters:
335060225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3351a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
33522c9a7b26SBarry Smith - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()`
3353552f7358SJed Brown 
3354552f7358SJed Brown   Level: beginner
3355552f7358SJed Brown 
3356a1cb98faSBarry Smith   Note:
3357a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3358a1cb98faSBarry Smith 
33591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3360552f7358SJed Brown @*/
3361d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3362d71ae5a4SJacob Faibussowitsch {
3363552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3364552f7358SJed Brown   PetscInt dof, off, c;
3365552f7358SJed Brown 
3366552f7358SJed Brown   PetscFunctionBegin;
3367552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
33694f572ea9SToby Isaac   if (dof) PetscAssertPointer(cone, 3);
33709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3371db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3372db485b19SStefano Zampini     PetscInt pStart, pEnd;
3373db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
337463a3b9bcSJacob 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);
3375552f7358SJed Brown     for (c = 0; c < dof; ++c) {
337663a3b9bcSJacob 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);
3377552f7358SJed Brown       mesh->cones[off + c] = cone[c];
3378552f7358SJed Brown     }
3379db485b19SStefano Zampini   } else {
3380db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3381db485b19SStefano Zampini   }
33823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3383552f7358SJed Brown }
3384552f7358SJed Brown 
3385552f7358SJed Brown /*@C
3386eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3387552f7358SJed Brown 
3388a1cb98faSBarry Smith   Not Collective
3389552f7358SJed Brown 
3390552f7358SJed Brown   Input Parameters:
339160225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3392a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3393552f7358SJed Brown 
3394552f7358SJed Brown   Output Parameter:
339520f4b53cSBarry Smith . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
33962c9a7b26SBarry Smith                     integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()`
3397552f7358SJed Brown 
3398552f7358SJed Brown   Level: beginner
3399552f7358SJed Brown 
3400a1cb98faSBarry Smith   Note:
3401b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3402b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3403a1cb98faSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3404b5a892a1SMatthew G. Knepley   with the identity.
3405b5a892a1SMatthew G. Knepley 
340660225df5SJacob Faibussowitsch   Fortran Notes:
34072c9a7b26SBarry Smith   You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3408a1cb98faSBarry Smith   `DMPlexRestoreConeOrientation()` is not needed/available in C.
34093813dfbdSMatthew G Knepley 
34102c9a7b26SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`,
34112c9a7b26SBarry Smith           `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3412552f7358SJed Brown @*/
3413d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3414d71ae5a4SJacob Faibussowitsch {
3415552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3416552f7358SJed Brown   PetscInt off;
3417552f7358SJed Brown 
3418552f7358SJed Brown   PetscFunctionBegin;
3419552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
342076bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3421552f7358SJed Brown     PetscInt dof;
34229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
34234f572ea9SToby Isaac     if (dof) PetscAssertPointer(coneOrientation, 3);
3424552f7358SJed Brown   }
34259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
34260d644c17SKarl Rupp 
3427552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
34283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3429552f7358SJed Brown }
3430552f7358SJed Brown 
3431552f7358SJed Brown /*@
3432eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3433552f7358SJed Brown 
3434a1cb98faSBarry Smith   Not Collective
3435552f7358SJed Brown 
3436552f7358SJed Brown   Input Parameters:
343760225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3438a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
34392c9a7b26SBarry Smith - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()`
3440b5a892a1SMatthew G. Knepley 
3441552f7358SJed Brown   Level: beginner
3442552f7358SJed Brown 
3443a1cb98faSBarry Smith   Notes:
3444a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3445a1cb98faSBarry Smith 
3446a1cb98faSBarry Smith   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3447a1cb98faSBarry Smith 
34481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3449552f7358SJed Brown @*/
3450d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3451d71ae5a4SJacob Faibussowitsch {
3452552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3453552f7358SJed Brown   PetscInt pStart, pEnd;
3454552f7358SJed Brown   PetscInt dof, off, c;
3455552f7358SJed Brown 
3456552f7358SJed Brown   PetscFunctionBegin;
3457552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
34594f572ea9SToby Isaac   if (dof) PetscAssertPointer(coneOrientation, 3);
34609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3461db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3462db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
346363a3b9bcSJacob 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);
3464552f7358SJed Brown     for (c = 0; c < dof; ++c) {
3465552f7358SJed Brown       PetscInt cdof, o = coneOrientation[c];
3466552f7358SJed Brown 
34679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
34681dca8a05SBarry 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);
3469552f7358SJed Brown       mesh->coneOrientations[off + c] = o;
3470552f7358SJed Brown     }
3471db485b19SStefano Zampini   } else {
3472db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3473db485b19SStefano Zampini   }
34743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3475552f7358SJed Brown }
3476552f7358SJed Brown 
34777cd05799SMatthew G. Knepley /*@
3478eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
34797cd05799SMatthew G. Knepley 
3480a1cb98faSBarry Smith   Not Collective
34817cd05799SMatthew G. Knepley 
34827cd05799SMatthew G. Knepley   Input Parameters:
348360225df5SJacob Faibussowitsch + dm        - The `DMPLEX`
3484a1cb98faSBarry Smith . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
34857cd05799SMatthew G. Knepley . conePos   - The local index in the cone where the point should be put
34867cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
34877cd05799SMatthew G. Knepley 
34887cd05799SMatthew G. Knepley   Level: beginner
34897cd05799SMatthew G. Knepley 
34901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
34917cd05799SMatthew G. Knepley @*/
3492d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3493d71ae5a4SJacob Faibussowitsch {
3494552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3495552f7358SJed Brown   PetscInt pStart, pEnd;
3496552f7358SJed Brown   PetscInt dof, off;
3497552f7358SJed Brown 
3498552f7358SJed Brown   PetscFunctionBegin;
3499552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3500a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
35019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
350263a3b9bcSJacob 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);
350363a3b9bcSJacob 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);
35049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
350563a3b9bcSJacob 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);
3506a03d55ffSStefano Zampini   }
3507a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3508552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
35093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3510552f7358SJed Brown }
3511552f7358SJed Brown 
35127cd05799SMatthew G. Knepley /*@
3513eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
35147cd05799SMatthew G. Knepley 
3515a1cb98faSBarry Smith   Not Collective
35167cd05799SMatthew G. Knepley 
35177cd05799SMatthew G. Knepley   Input Parameters:
351860225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3519a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
35207cd05799SMatthew G. Knepley . conePos         - The local index in the cone where the point should be put
35217cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
35227cd05799SMatthew G. Knepley 
35237cd05799SMatthew G. Knepley   Level: beginner
35247cd05799SMatthew G. Knepley 
3525a1cb98faSBarry Smith   Note:
3526a1cb98faSBarry Smith   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3527b5a892a1SMatthew G. Knepley 
35281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
35297cd05799SMatthew G. Knepley @*/
3530d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3531d71ae5a4SJacob Faibussowitsch {
353277c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
353377c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
353477c88f5bSMatthew G Knepley   PetscInt dof, off;
353577c88f5bSMatthew G Knepley 
353677c88f5bSMatthew G Knepley   PetscFunctionBegin;
353777c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3538a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
35399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
354063a3b9bcSJacob 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);
35419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
354263a3b9bcSJacob 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);
3543a03d55ffSStefano Zampini   }
3544a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
354577c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
35463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
354777c88f5bSMatthew G Knepley }
354877c88f5bSMatthew G Knepley 
35499f4ada15SMatthew G. Knepley /*@C
35509f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
35519f4ada15SMatthew G. Knepley 
35529f4ada15SMatthew G. Knepley   Not collective
35539f4ada15SMatthew G. Knepley 
35549f4ada15SMatthew G. Knepley   Input Parameters:
35559f4ada15SMatthew G. Knepley + dm - The DMPlex
35569f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
35579f4ada15SMatthew G. Knepley 
35589f4ada15SMatthew G. Knepley   Output Parameters:
355920f4b53cSBarry Smith + cone - An array of points which are on the in-edges for point `p`
356020f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
35619f4ada15SMatthew G. Knepley          integer giving the prescription for cone traversal.
35629f4ada15SMatthew G. Knepley 
35639f4ada15SMatthew G. Knepley   Level: beginner
35649f4ada15SMatthew G. Knepley 
35659f4ada15SMatthew G. Knepley   Notes:
35669f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
35679f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
356820f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
35699f4ada15SMatthew G. Knepley   with the identity.
35709f4ada15SMatthew G. Knepley 
35712c9a7b26SBarry Smith   You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array.
35722c9a7b26SBarry Smith 
35739f4ada15SMatthew G. Knepley   Fortran Notes:
35742c9a7b26SBarry Smith   `cone` and `ornt` must be declared with
35752c9a7b26SBarry Smith .vb
35762c9a7b26SBarry Smith   PetscInt, pointer :: cone(:)
35772c9a7b26SBarry Smith   PetscInt, pointer :: ornt(:)
35782c9a7b26SBarry Smith .ve
35799f4ada15SMatthew G. Knepley 
35801cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
35819f4ada15SMatthew G. Knepley @*/
35829f4ada15SMatthew G. Knepley PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
35839f4ada15SMatthew G. Knepley {
35849f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
35859f4ada15SMatthew G. Knepley 
35869f4ada15SMatthew G. Knepley   PetscFunctionBegin;
35879f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35889f4ada15SMatthew G. Knepley   if (mesh->tr) {
35899f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
35909f4ada15SMatthew G. Knepley   } else {
35919f4ada15SMatthew G. Knepley     PetscInt off;
35929f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
35939f4ada15SMatthew G. Knepley       PetscInt dof;
35949f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
35959f4ada15SMatthew G. Knepley       if (dof) {
35964f572ea9SToby Isaac         if (cone) PetscAssertPointer(cone, 3);
35974f572ea9SToby Isaac         if (ornt) PetscAssertPointer(ornt, 4);
35989f4ada15SMatthew G. Knepley       }
35999f4ada15SMatthew G. Knepley     }
36009f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
36018e3a54c0SPierre Jolivet     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
36028e3a54c0SPierre Jolivet     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
36039f4ada15SMatthew G. Knepley   }
36043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36059f4ada15SMatthew G. Knepley }
36069f4ada15SMatthew G. Knepley 
36079f4ada15SMatthew G. Knepley /*@C
36082c9a7b26SBarry Smith   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()`
36099f4ada15SMatthew G. Knepley 
361020f4b53cSBarry Smith   Not Collective
36119f4ada15SMatthew G. Knepley 
36129f4ada15SMatthew G. Knepley   Input Parameters:
36139f4ada15SMatthew G. Knepley + dm   - The DMPlex
361420f4b53cSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
36159f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
361620f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
36179f4ada15SMatthew G. Knepley          integer giving the prescription for cone traversal.
36189f4ada15SMatthew G. Knepley 
36199f4ada15SMatthew G. Knepley   Level: beginner
36209f4ada15SMatthew G. Knepley 
36211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
36229f4ada15SMatthew G. Knepley @*/
36239f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
36249f4ada15SMatthew G. Knepley {
36259f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
36269f4ada15SMatthew G. Knepley 
36279f4ada15SMatthew G. Knepley   PetscFunctionBegin;
36289f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36299f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
36303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36319f4ada15SMatthew G. Knepley }
36329f4ada15SMatthew G. Knepley 
3633552f7358SJed Brown /*@
3634eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3635552f7358SJed Brown 
3636a1cb98faSBarry Smith   Not Collective
3637552f7358SJed Brown 
3638552f7358SJed Brown   Input Parameters:
363960225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3640a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3641552f7358SJed Brown 
3642552f7358SJed Brown   Output Parameter:
364320f4b53cSBarry Smith . size - The support size for point `p`
3644552f7358SJed Brown 
3645552f7358SJed Brown   Level: beginner
3646552f7358SJed Brown 
36471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3648552f7358SJed Brown @*/
3649d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3650d71ae5a4SJacob Faibussowitsch {
3651552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3652552f7358SJed Brown 
3653552f7358SJed Brown   PetscFunctionBegin;
3654552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36554f572ea9SToby Isaac   PetscAssertPointer(size, 3);
36569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
36573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3658552f7358SJed Brown }
3659552f7358SJed Brown 
3660552f7358SJed Brown /*@
3661eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3662552f7358SJed Brown 
3663a1cb98faSBarry Smith   Not Collective
3664552f7358SJed Brown 
3665552f7358SJed Brown   Input Parameters:
366660225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3667a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
366820f4b53cSBarry Smith - size - The support size for point `p`
3669552f7358SJed Brown 
3670a1cb98faSBarry Smith   Level: beginner
3671552f7358SJed Brown 
3672552f7358SJed Brown   Note:
367320f4b53cSBarry Smith   This should be called after `DMPlexSetChart()`.
3674552f7358SJed Brown 
36751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3676552f7358SJed Brown @*/
3677d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3678d71ae5a4SJacob Faibussowitsch {
3679552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3680552f7358SJed Brown 
3681552f7358SJed Brown   PetscFunctionBegin;
3682552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36839566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
36843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3685552f7358SJed Brown }
3686552f7358SJed Brown 
3687552f7358SJed Brown /*@C
3688eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3689552f7358SJed Brown 
3690a1cb98faSBarry Smith   Not Collective
3691552f7358SJed Brown 
3692552f7358SJed Brown   Input Parameters:
369360225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3694a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3695552f7358SJed Brown 
3696552f7358SJed Brown   Output Parameter:
36972c9a7b26SBarry Smith . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3698552f7358SJed Brown 
3699552f7358SJed Brown   Level: beginner
3700552f7358SJed Brown 
370160225df5SJacob Faibussowitsch   Fortran Notes:
37022c9a7b26SBarry Smith   `support` must be declared with
37032c9a7b26SBarry Smith .vb
37042c9a7b26SBarry Smith   PetscInt, pointer :: support(:)
37052c9a7b26SBarry Smith .ve
37062c9a7b26SBarry Smith 
3707a1cb98faSBarry Smith   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3708a1cb98faSBarry Smith   `DMPlexRestoreSupport()` is not needed/available in C.
37093813dfbdSMatthew G Knepley 
37101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3711552f7358SJed Brown @*/
3712d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3713d71ae5a4SJacob Faibussowitsch {
3714552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3715552f7358SJed Brown   PetscInt off;
3716552f7358SJed Brown 
3717552f7358SJed Brown   PetscFunctionBegin;
3718552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37194f572ea9SToby Isaac   PetscAssertPointer(support, 3);
37209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
37218e3a54c0SPierre Jolivet   *support = PetscSafePointerPlusOffset(mesh->supports, off);
37223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3723552f7358SJed Brown }
3724552f7358SJed Brown 
3725552f7358SJed Brown /*@
372692371b87SBarry 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
3727552f7358SJed Brown 
3728a1cb98faSBarry Smith   Not Collective
3729552f7358SJed Brown 
3730552f7358SJed Brown   Input Parameters:
373160225df5SJacob Faibussowitsch + dm      - The `DMPLEX`
3732a1cb98faSBarry Smith . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
37332c9a7b26SBarry Smith - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()`
3734552f7358SJed Brown 
3735552f7358SJed Brown   Level: beginner
3736552f7358SJed Brown 
3737a1cb98faSBarry Smith   Note:
3738a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3739a1cb98faSBarry Smith 
37401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3741552f7358SJed Brown @*/
3742d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3743d71ae5a4SJacob Faibussowitsch {
3744552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3745552f7358SJed Brown   PetscInt pStart, pEnd;
3746552f7358SJed Brown   PetscInt dof, off, c;
3747552f7358SJed Brown 
3748552f7358SJed Brown   PetscFunctionBegin;
3749552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
37519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
37524f572ea9SToby Isaac   if (dof) PetscAssertPointer(support, 3);
37539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
375463a3b9bcSJacob 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);
3755552f7358SJed Brown   for (c = 0; c < dof; ++c) {
375663a3b9bcSJacob 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);
3757552f7358SJed Brown     mesh->supports[off + c] = support[c];
3758552f7358SJed Brown   }
37593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3760552f7358SJed Brown }
3761552f7358SJed Brown 
37627cd05799SMatthew G. Knepley /*@
3763eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
37647cd05799SMatthew G. Knepley 
3765a1cb98faSBarry Smith   Not Collective
37667cd05799SMatthew G. Knepley 
37677cd05799SMatthew G. Knepley   Input Parameters:
376860225df5SJacob Faibussowitsch + dm           - The `DMPLEX`
3769a1cb98faSBarry Smith . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
37707cd05799SMatthew G. Knepley . supportPos   - The local index in the cone where the point should be put
37717cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
37727cd05799SMatthew G. Knepley 
37737cd05799SMatthew G. Knepley   Level: beginner
37747cd05799SMatthew G. Knepley 
37751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
37767cd05799SMatthew G. Knepley @*/
3777d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3778d71ae5a4SJacob Faibussowitsch {
3779552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3780552f7358SJed Brown   PetscInt pStart, pEnd;
3781552f7358SJed Brown   PetscInt dof, off;
3782552f7358SJed Brown 
3783552f7358SJed Brown   PetscFunctionBegin;
3784552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
37869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
37879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
378863a3b9bcSJacob 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);
378963a3b9bcSJacob 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);
379063a3b9bcSJacob 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);
3791552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
37923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3793552f7358SJed Brown }
3794552f7358SJed Brown 
3795b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3796d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3797d71ae5a4SJacob Faibussowitsch {
3798b5a892a1SMatthew G. Knepley   switch (ct) {
3799b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3800b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3801b5a892a1SMatthew G. Knepley     break;
3802b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3803b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3804b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3805b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3806b5a892a1SMatthew G. Knepley     break;
3807b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3808b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3809b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3810b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3811b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3812b5a892a1SMatthew G. Knepley     break;
3813d71ae5a4SJacob Faibussowitsch   default:
3814d71ae5a4SJacob Faibussowitsch     return o;
3815b5a892a1SMatthew G. Knepley   }
3816b5a892a1SMatthew G. Knepley   return o;
3817b5a892a1SMatthew G. Knepley }
3818b5a892a1SMatthew G. Knepley 
3819b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3820d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3821d71ae5a4SJacob Faibussowitsch {
3822b5a892a1SMatthew G. Knepley   switch (ct) {
3823b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3824b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3825b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3826b5a892a1SMatthew G. Knepley     break;
3827b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3828b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3829b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3830b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3831b5a892a1SMatthew G. Knepley     break;
3832b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3833b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3834b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3835b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3836b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3837b5a892a1SMatthew G. Knepley     break;
3838d71ae5a4SJacob Faibussowitsch   default:
3839d71ae5a4SJacob Faibussowitsch     return o;
3840b5a892a1SMatthew G. Knepley   }
3841b5a892a1SMatthew G. Knepley   return o;
3842b5a892a1SMatthew G. Knepley }
3843b5a892a1SMatthew G. Knepley 
3844b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3845d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3846d71ae5a4SJacob Faibussowitsch {
3847b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3848b5a892a1SMatthew G. Knepley 
3849b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
38509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3851b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3852b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3853b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3854b5a892a1SMatthew G. Knepley 
38559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
38569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
38579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3858b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3859b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3860b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3861b5a892a1SMatthew G. Knepley 
38629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3863b5a892a1SMatthew G. Knepley       switch (ct) {
3864b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
38659566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
38669566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3867b5a892a1SMatthew G. Knepley         break;
3868b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
38699566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
38709566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
38719566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3872b5a892a1SMatthew G. Knepley         break;
3873b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
38749566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
38759566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
38769566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
38779566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3878b5a892a1SMatthew G. Knepley         break;
3879d71ae5a4SJacob Faibussowitsch       default:
3880d71ae5a4SJacob Faibussowitsch         break;
3881b5a892a1SMatthew G. Knepley       }
3882b5a892a1SMatthew G. Knepley     }
3883b5a892a1SMatthew G. Knepley   }
38843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3885b5a892a1SMatthew G. Knepley }
3886b5a892a1SMatthew G. Knepley 
388709015e70SStefano Zampini static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
388809015e70SStefano Zampini {
388909015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
389009015e70SStefano Zampini 
389109015e70SStefano Zampini   PetscFunctionBeginHot;
389209015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
389309015e70SStefano Zampini     if (useCone) {
389409015e70SStefano Zampini       PetscCall(DMPlexGetConeSize(dm, p, size));
389509015e70SStefano Zampini       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
389609015e70SStefano Zampini     } else {
389709015e70SStefano Zampini       PetscCall(DMPlexGetSupportSize(dm, p, size));
389809015e70SStefano Zampini       PetscCall(DMPlexGetSupport(dm, p, arr));
389909015e70SStefano Zampini     }
390009015e70SStefano Zampini   } else {
390109015e70SStefano Zampini     if (useCone) {
390209015e70SStefano Zampini       const PetscSection s   = mesh->coneSection;
390309015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
390409015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
390509015e70SStefano Zampini 
390609015e70SStefano Zampini       *size = s->atlasDof[ps];
390709015e70SStefano Zampini       *arr  = mesh->cones + off;
390809015e70SStefano Zampini       *ornt = mesh->coneOrientations + off;
390909015e70SStefano Zampini     } else {
391009015e70SStefano Zampini       const PetscSection s   = mesh->supportSection;
391109015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
391209015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
391309015e70SStefano Zampini 
391409015e70SStefano Zampini       *size = s->atlasDof[ps];
391509015e70SStefano Zampini       *arr  = mesh->supports + off;
391609015e70SStefano Zampini     }
391709015e70SStefano Zampini   }
391809015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
391909015e70SStefano Zampini }
392009015e70SStefano Zampini 
392109015e70SStefano Zampini static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
392209015e70SStefano Zampini {
392309015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
392409015e70SStefano Zampini 
392509015e70SStefano Zampini   PetscFunctionBeginHot;
392609015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
392709015e70SStefano Zampini     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
392809015e70SStefano Zampini   }
392909015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
393009015e70SStefano Zampini }
393109015e70SStefano Zampini 
3932d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3933d71ae5a4SJacob Faibussowitsch {
3934b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3935b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3936b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3937b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3938b5a892a1SMatthew G. Knepley 
3939b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3940b5a892a1SMatthew G. Knepley   if (ornt) {
39419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3942476787b7SMatthew 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;
3943b5a892a1SMatthew G. Knepley   }
3944b5a892a1SMatthew G. Knepley   if (*points) {
3945b5a892a1SMatthew G. Knepley     closure = *points;
3946b5a892a1SMatthew G. Knepley   } else {
3947b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
39489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
39499566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3950b5a892a1SMatthew G. Knepley   }
395109015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3952b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3953b5a892a1SMatthew G. Knepley     closure[off++] = p;
3954b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3955b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3956b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3957b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3958b5a892a1SMatthew G. Knepley     }
3959b5a892a1SMatthew G. Knepley   } else {
396085036b15SMatthew G. Knepley     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);
3961b5a892a1SMatthew G. Knepley 
3962b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3963b5a892a1SMatthew G. Knepley     closure[off++] = p;
3964b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3965b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3966b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3967b5a892a1SMatthew G. Knepley 
39689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3969b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3970b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3971b5a892a1SMatthew G. Knepley     }
3972b5a892a1SMatthew G. Knepley   }
397309015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3974b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
3975b5a892a1SMatthew G. Knepley   if (points) *points = closure;
39763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3977b5a892a1SMatthew G. Knepley }
3978b5a892a1SMatthew G. Knepley 
3979d5b43468SJose E. Roman /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3980d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3981d71ae5a4SJacob Faibussowitsch {
398285036b15SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
3983b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3984b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
3985b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3986b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3987b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3988b5a892a1SMatthew G. Knepley 
3989b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
39909566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
399109015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
39929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3993b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3994b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3995b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
39969371c9d4SSatish Balay   if (*points) {
39979371c9d4SSatish Balay     pts = *points;
39989371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3999b5a892a1SMatthew G. Knepley   c        = 0;
4000b5a892a1SMatthew G. Knepley   pts[c++] = point;
4001b5a892a1SMatthew G. Knepley   pts[c++] = o;
40029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
40039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
40049371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
40059371c9d4SSatish Balay     pts[c++] = closure[cl];
40069371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
40079371c9d4SSatish Balay   }
40089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
40099371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
40109371c9d4SSatish Balay     pts[c++] = closure[cl];
40119371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
40129371c9d4SSatish Balay   }
40139566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
4014b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
40159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
4016b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
4017b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
4018b5a892a1SMatthew G. Knepley   }
401909015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
4020b5a892a1SMatthew G. Knepley   if (dim >= 3) {
4021b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
4022b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
4023b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
4024b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
4025b5a892a1SMatthew G. Knepley 
40269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
402785036b15SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
402809015e70SStefano Zampini       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4029b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
4030b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
4031b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
4032b5a892a1SMatthew G. Knepley 
40339371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
40349371c9d4SSatish Balay           if (pts[i] == cp) break;
4035b5a892a1SMatthew G. Knepley         if (i == c) {
40369566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
4037b5a892a1SMatthew G. Knepley           pts[c++] = cp;
4038b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
4039b5a892a1SMatthew G. Knepley         }
4040b5a892a1SMatthew G. Knepley       }
404109015e70SStefano Zampini       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
4042b5a892a1SMatthew G. Knepley     }
4043b5a892a1SMatthew G. Knepley   }
4044b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
4045b5a892a1SMatthew G. Knepley   *points    = pts;
40463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4047b5a892a1SMatthew G. Knepley }
4048b5a892a1SMatthew G. Knepley 
4049d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4050d71ae5a4SJacob Faibussowitsch {
4051b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
4052b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
4053b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
4054b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
4055b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
4056b5a892a1SMatthew G. Knepley 
4057b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
40589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
4059b5a892a1SMatthew G. Knepley   if (depth == 1) {
40609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
40613ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4062b5a892a1SMatthew G. Knepley   }
40639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
4064476787b7SMatthew 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;
4065c306944fSJed Brown   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
40669566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
40673ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4068b5a892a1SMatthew G. Knepley   }
40699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
4070b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
4071b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
4072b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
40739566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
40749371c9d4SSatish Balay   if (*points) {
40759371c9d4SSatish Balay     closure = *points;
40769371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
4077b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
4078b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
4079b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
4080b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
4081b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
4082b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
4083b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
4084b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
4085b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
4086b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
408785036b15SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
408809015e70SStefano Zampini     const PetscInt      *tmp, *tmpO = NULL;
4089b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
4090b5a892a1SMatthew G. Knepley 
4091b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
409285036b15SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
409363a3b9bcSJacob 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);
4094b5a892a1SMatthew G. Knepley     }
409509015e70SStefano Zampini     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4096b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4097b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4098b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4099b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
41009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4101b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4102b5a892a1SMatthew G. Knepley       PetscInt       c;
4103b5a892a1SMatthew G. Knepley 
4104b5a892a1SMatthew G. Knepley       /* Check for duplicate */
4105b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
4106b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
4107b5a892a1SMatthew G. Knepley       }
4108b5a892a1SMatthew G. Knepley       if (c == closureSize) {
4109b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
4110b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
4111b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
4112b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
4113b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
4114b5a892a1SMatthew G. Knepley       }
4115b5a892a1SMatthew G. Knepley     }
411609015e70SStefano Zampini     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4117b5a892a1SMatthew G. Knepley   }
41189566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4119b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
4120b5a892a1SMatthew G. Knepley   if (points) *points = closure;
41213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4122b5a892a1SMatthew G. Knepley }
4123b5a892a1SMatthew G. Knepley 
4124552f7358SJed Brown /*@C
4125eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
4126552f7358SJed Brown 
4127a1cb98faSBarry Smith   Not Collective
4128552f7358SJed Brown 
4129552f7358SJed Brown   Input Parameters:
4130a1cb98faSBarry Smith + dm      - The `DMPLEX`
4131b5a892a1SMatthew G. Knepley . p       - The mesh point
4132a1cb98faSBarry Smith - useCone - `PETSC_TRUE` for the closure, otherwise return the star
4133552f7358SJed Brown 
41346b867d5aSJose E. Roman   Input/Output Parameter:
41356b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
41362c9a7b26SBarry Smith            if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`,
41372c9a7b26SBarry Smith            otherwise the provided array is used to hold the values
41386b867d5aSJose E. Roman 
41396b867d5aSJose E. Roman   Output Parameter:
41402c9a7b26SBarry Smith . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints`
4141552f7358SJed Brown 
4142a1cb98faSBarry Smith   Level: beginner
4143a1cb98faSBarry Smith 
4144552f7358SJed Brown   Note:
414520f4b53cSBarry Smith   If using internal storage (points is `NULL` on input), each call overwrites the last output.
4146552f7358SJed Brown 
414760225df5SJacob Faibussowitsch   Fortran Notes:
41482c9a7b26SBarry Smith   `points` must be declared with
41492c9a7b26SBarry Smith .vb
41502c9a7b26SBarry Smith   PetscInt, pointer :: points(:)
41512c9a7b26SBarry Smith .ve
41522c9a7b26SBarry Smith   and is always allocated by the function.
41532c9a7b26SBarry Smith 
41542c9a7b26SBarry Smith   The `numPoints` argument is not present in the Fortran binding.
41553813dfbdSMatthew G Knepley 
41561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4157552f7358SJed Brown @*/
4158d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4159d71ae5a4SJacob Faibussowitsch {
4160b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4161552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41624f572ea9SToby Isaac   if (numPoints) PetscAssertPointer(numPoints, 4);
41634f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 5);
4164332e0eaaSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) {
4165332e0eaaSMatthew G. Knepley     PetscInt pStart, pEnd;
4166332e0eaaSMatthew G. Knepley     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4167332e0eaaSMatthew 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);
4168332e0eaaSMatthew G. Knepley   }
41699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
41703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41719bf0dad6SMatthew G. Knepley }
41729bf0dad6SMatthew G. Knepley 
4173552f7358SJed Brown /*@C
4174eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
4175552f7358SJed Brown 
4176a1cb98faSBarry Smith   Not Collective
4177552f7358SJed Brown 
4178552f7358SJed Brown   Input Parameters:
4179a1cb98faSBarry Smith + dm        - The `DMPLEX`
4180b5a892a1SMatthew G. Knepley . p         - The mesh point
4181a1cb98faSBarry Smith . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
418220f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4183b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
4184552f7358SJed Brown 
4185a1cb98faSBarry Smith   Level: beginner
4186a1cb98faSBarry Smith 
4187552f7358SJed Brown   Note:
418820f4b53cSBarry Smith   If not using internal storage (points is not `NULL` on input), this call is unnecessary
4189552f7358SJed Brown 
41901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4191552f7358SJed Brown @*/
4192d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4193d71ae5a4SJacob Faibussowitsch {
4194b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4195552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41964ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
41979566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
41983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4199552f7358SJed Brown }
4200552f7358SJed Brown 
4201552f7358SJed Brown /*@
4202eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
4203552f7358SJed Brown 
4204a1cb98faSBarry Smith   Not Collective
4205552f7358SJed Brown 
4206552f7358SJed Brown   Input Parameter:
420760225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4208552f7358SJed Brown 
4209552f7358SJed Brown   Output Parameters:
4210552f7358SJed Brown + maxConeSize    - The maximum number of in-edges
4211552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
4212552f7358SJed Brown 
4213552f7358SJed Brown   Level: beginner
4214552f7358SJed Brown 
42151cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4216552f7358SJed Brown @*/
4217d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
4218d71ae5a4SJacob Faibussowitsch {
4219552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
4220552f7358SJed Brown 
4221552f7358SJed Brown   PetscFunctionBegin;
4222552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42231baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
42241baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
42253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4226552f7358SJed Brown }
4227552f7358SJed Brown 
4228d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
4229d71ae5a4SJacob Faibussowitsch {
4230552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
42316302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
4232552f7358SJed Brown 
4233552f7358SJed Brown   PetscFunctionBegin;
4234552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42359566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
42369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
42379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
42389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
42396302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
42406302a7fbSVaclav Hapla   if (maxSupportSize) {
42419566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
42429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
42439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
4244552f7358SJed Brown   }
42453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4246552f7358SJed Brown }
4247552f7358SJed Brown 
4248d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4249d71ae5a4SJacob Faibussowitsch {
4250552f7358SJed Brown   PetscFunctionBegin;
42519566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
4252dd072f5fSMatthew G. Knepley   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
4253ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
4254736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
425595602cf2SAlexis Marboeuf     PetscSF sfNatural;
4256f94b4a02SBlaise Bourdin 
42573dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
42589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
425995602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4260c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
4261f94b4a02SBlaise Bourdin   }
42623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4263552f7358SJed Brown }
4264552f7358SJed Brown 
4265d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4266d71ae5a4SJacob Faibussowitsch {
42673dcd263cSBlaise Bourdin   PetscInt i = 0;
42682adcc780SMatthew G. Knepley 
42692adcc780SMatthew G. Knepley   PetscFunctionBegin;
42709566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
42719566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4272c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
42733dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
42743dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
427595602cf2SAlexis Marboeuf       PetscSF sfNatural;
42763dcd263cSBlaise Bourdin 
42773dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
42789566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4279c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
428095602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4281c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
42823dcd263cSBlaise Bourdin       break;
42833dcd263cSBlaise Bourdin     }
42843dcd263cSBlaise Bourdin   }
42853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42862adcc780SMatthew G. Knepley }
42872adcc780SMatthew G. Knepley 
4288552f7358SJed Brown /*@
4289eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4290552f7358SJed Brown 
4291a1cb98faSBarry Smith   Not Collective
4292552f7358SJed Brown 
4293552f7358SJed Brown   Input Parameter:
429460225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4295552f7358SJed Brown 
4296552f7358SJed Brown   Level: beginner
4297552f7358SJed Brown 
4298a1cb98faSBarry Smith   Note:
4299a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetCone()`
4300a1cb98faSBarry Smith 
43011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4302552f7358SJed Brown @*/
4303d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
4304d71ae5a4SJacob Faibussowitsch {
4305552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4306552f7358SJed Brown   PetscInt *offsets;
4307552f7358SJed Brown   PetscInt  supportSize;
4308552f7358SJed Brown   PetscInt  pStart, pEnd, p;
4309552f7358SJed Brown 
4310552f7358SJed Brown   PetscFunctionBegin;
4311552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
431228b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
43139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4314552f7358SJed Brown   /* Calculate support sizes */
43159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4316552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4317552f7358SJed Brown     PetscInt dof, off, c;
4318552f7358SJed Brown 
43199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
43209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
432148a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4322552f7358SJed Brown   }
43239566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
4324552f7358SJed Brown   /* Calculate supports */
43259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
43269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
43279566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4328552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4329552f7358SJed Brown     PetscInt dof, off, c;
4330552f7358SJed Brown 
43319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
43329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4333552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
4334552f7358SJed Brown       const PetscInt q = mesh->cones[c];
4335552f7358SJed Brown       PetscInt       offS;
4336552f7358SJed Brown 
43379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
43380d644c17SKarl Rupp 
4339552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
4340552f7358SJed Brown       ++offsets[q];
4341552f7358SJed Brown     }
4342552f7358SJed Brown   }
43439566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
43449566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
43453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4346552f7358SJed Brown }
4347552f7358SJed Brown 
4348d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4349d71ae5a4SJacob Faibussowitsch {
4350277ea44aSLisandro Dalcin   IS stratumIS;
4351277ea44aSLisandro Dalcin 
4352277ea44aSLisandro Dalcin   PetscFunctionBegin;
43533ba16761SJacob Faibussowitsch   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
435476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4355277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4356277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
43579566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4358277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
43599566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
43609371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
43619371c9d4SSatish Balay         overlap = PETSC_TRUE;
43629371c9d4SSatish Balay         break;
43639371c9d4SSatish Balay       }
4364277ea44aSLisandro Dalcin     }
436563a3b9bcSJacob 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);
4366277ea44aSLisandro Dalcin   }
43679566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
43689566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
43699566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
43703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4371277ea44aSLisandro Dalcin }
4372277ea44aSLisandro Dalcin 
4373e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4374e91fa0a1SMatthew G. Knepley {
4375e91fa0a1SMatthew G. Knepley   PetscInt *pMin, *pMax;
4376e91fa0a1SMatthew G. Knepley   PetscInt  pStart, pEnd;
4377e91fa0a1SMatthew G. Knepley   PetscInt  dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT;
4378e91fa0a1SMatthew G. Knepley 
4379e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4380e91fa0a1SMatthew G. Knepley   {
4381e91fa0a1SMatthew G. Knepley     DMLabel label2;
4382e91fa0a1SMatthew G. Knepley 
4383e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4384e91fa0a1SMatthew G. Knepley     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4385e91fa0a1SMatthew G. Knepley   }
4386e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4387e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4388e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4389e91fa0a1SMatthew G. Knepley 
4390e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4391e91fa0a1SMatthew G. Knepley     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4392e91fa0a1SMatthew G. Knepley     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4393e91fa0a1SMatthew G. Knepley   }
4394e91fa0a1SMatthew G. Knepley   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4395e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4396e91fa0a1SMatthew G. Knepley     pMin[d] = PETSC_MAX_INT;
4397e91fa0a1SMatthew G. Knepley     pMax[d] = PETSC_MIN_INT;
4398e91fa0a1SMatthew G. Knepley   }
4399e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4400e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4401e91fa0a1SMatthew G. Knepley     PetscInt       d;
4402e91fa0a1SMatthew G. Knepley 
4403e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4404e91fa0a1SMatthew G. Knepley     d       = DMPolytopeTypeGetDim(ct);
4405e91fa0a1SMatthew G. Knepley     pMin[d] = PetscMin(p, pMin[d]);
4406e91fa0a1SMatthew G. Knepley     pMax[d] = PetscMax(p, pMax[d]);
4407e91fa0a1SMatthew G. Knepley   }
4408e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4409e91fa0a1SMatthew G. Knepley     if (pMin[d] > pMax[d]) continue;
4410e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4411e91fa0a1SMatthew G. Knepley   }
4412e91fa0a1SMatthew G. Knepley   PetscCall(PetscFree2(pMin, pMax));
4413e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4414e91fa0a1SMatthew G. Knepley }
4415e91fa0a1SMatthew G. Knepley 
4416e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4417e91fa0a1SMatthew G. Knepley {
4418e91fa0a1SMatthew G. Knepley   PetscInt pStart, pEnd;
4419e91fa0a1SMatthew G. Knepley   PetscInt numRoots = 0, numLeaves = 0;
4420e91fa0a1SMatthew G. Knepley 
4421e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4422e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4423e91fa0a1SMatthew G. Knepley   {
4424e91fa0a1SMatthew G. Knepley     /* Initialize roots and count leaves */
4425e91fa0a1SMatthew G. Knepley     PetscInt sMin = PETSC_MAX_INT;
4426e91fa0a1SMatthew G. Knepley     PetscInt sMax = PETSC_MIN_INT;
4427e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4428e91fa0a1SMatthew G. Knepley 
4429e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4430e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4431e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4432e91fa0a1SMatthew G. Knepley       if (!coneSize && supportSize) {
4433e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4434e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4435e91fa0a1SMatthew G. Knepley         ++numRoots;
4436e91fa0a1SMatthew G. Knepley       } else if (!supportSize && coneSize) {
4437e91fa0a1SMatthew G. Knepley         ++numLeaves;
4438e91fa0a1SMatthew G. Knepley       } else if (!supportSize && !coneSize) {
4439e91fa0a1SMatthew G. Knepley         /* Isolated points */
4440e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4441e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4442e91fa0a1SMatthew G. Knepley       }
4443e91fa0a1SMatthew G. Knepley     }
4444e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4445e91fa0a1SMatthew G. Knepley   }
4446e91fa0a1SMatthew G. Knepley 
4447e91fa0a1SMatthew G. Knepley   if (numRoots + numLeaves == (pEnd - pStart)) {
4448e91fa0a1SMatthew G. Knepley     PetscInt sMin = PETSC_MAX_INT;
4449e91fa0a1SMatthew G. Knepley     PetscInt sMax = PETSC_MIN_INT;
4450e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4451e91fa0a1SMatthew G. Knepley 
4452e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4453e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4454e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4455e91fa0a1SMatthew G. Knepley       if (!supportSize && coneSize) {
4456e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4457e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4458e91fa0a1SMatthew G. Knepley       }
4459e91fa0a1SMatthew G. Knepley     }
4460e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4461e91fa0a1SMatthew G. Knepley   } else {
4462e91fa0a1SMatthew G. Knepley     PetscInt level = 0;
4463e91fa0a1SMatthew G. Knepley     PetscInt qStart, qEnd;
4464e91fa0a1SMatthew G. Knepley 
4465e91fa0a1SMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4466e91fa0a1SMatthew G. Knepley     while (qEnd > qStart) {
4467e91fa0a1SMatthew G. Knepley       PetscInt sMin = PETSC_MAX_INT;
4468e91fa0a1SMatthew G. Knepley       PetscInt sMax = PETSC_MIN_INT;
4469e91fa0a1SMatthew G. Knepley 
4470e91fa0a1SMatthew G. Knepley       for (PetscInt q = qStart; q < qEnd; ++q) {
4471e91fa0a1SMatthew G. Knepley         const PetscInt *support;
4472e91fa0a1SMatthew G. Knepley         PetscInt        supportSize;
4473e91fa0a1SMatthew G. Knepley 
4474e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4475e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, q, &support));
4476e91fa0a1SMatthew G. Knepley         for (PetscInt s = 0; s < supportSize; ++s) {
4477e91fa0a1SMatthew G. Knepley           sMin = PetscMin(support[s], sMin);
4478e91fa0a1SMatthew G. Knepley           sMax = PetscMax(support[s], sMax);
4479e91fa0a1SMatthew G. Knepley         }
4480e91fa0a1SMatthew G. Knepley       }
4481e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetNumValues(label, &level));
4482e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4483e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4484e91fa0a1SMatthew G. Knepley     }
4485e91fa0a1SMatthew G. Knepley   }
4486e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4487e91fa0a1SMatthew G. Knepley }
4488e91fa0a1SMatthew G. Knepley 
4489552f7358SJed Brown /*@
4490a4e35b19SJacob Faibussowitsch   DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4491552f7358SJed Brown 
449220f4b53cSBarry Smith   Collective
4493552f7358SJed Brown 
4494552f7358SJed Brown   Input Parameter:
449560225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4496552f7358SJed Brown 
4497a1cb98faSBarry Smith   Level: beginner
4498552f7358SJed Brown 
4499552f7358SJed Brown   Notes:
4500a4e35b19SJacob Faibussowitsch   The strata group all points of the same grade, and this function calculates the strata. This
4501a4e35b19SJacob Faibussowitsch   grade can be seen as the height (or depth) of the point in the DAG.
4502a4e35b19SJacob Faibussowitsch 
4503a4e35b19SJacob Faibussowitsch   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4504a4e35b19SJacob Faibussowitsch   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4505a1cb98faSBarry Smith   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4506b1bb481bSMatthew 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
4507a1cb98faSBarry Smith   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4508a1cb98faSBarry Smith   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4509a1cb98faSBarry Smith   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4510552f7358SJed Brown 
4511b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4512b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4513b1bb481bSMatthew 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
4514b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4515a1cb98faSBarry Smith .vb
4516a1cb98faSBarry Smith   cone(c0) = {e0, v2}
4517a1cb98faSBarry Smith   cone(e0) = {v0, v1}
4518a1cb98faSBarry Smith .ve
4519a1cb98faSBarry Smith   If `DMPlexStratify()` is run on this mesh, it will give depths
4520a1cb98faSBarry Smith .vb
4521a1cb98faSBarry Smith    depth 0 = {v0, v1, v2}
4522a1cb98faSBarry Smith    depth 1 = {e0, c0}
4523a1cb98faSBarry Smith .ve
4524b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4525b1bb481bSMatthew Knepley 
4526a1cb98faSBarry Smith   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4527552f7358SJed Brown 
45281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4529552f7358SJed Brown @*/
4530d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4531d71ae5a4SJacob Faibussowitsch {
4532df0420ecSMatthew G. Knepley   DM_Plex  *mesh = (DM_Plex *)dm->data;
4533aa50250dSMatthew G. Knepley   DMLabel   label;
4534e91fa0a1SMatthew G. Knepley   PetscBool flg = PETSC_FALSE;
4535552f7358SJed Brown 
4536552f7358SJed Brown   PetscFunctionBegin;
4537552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
45389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4539277ea44aSLisandro Dalcin 
4540e91fa0a1SMatthew G. Knepley   // Create depth label
4541d28dd301SMatthew G. Knepley   PetscCall(DMRemoveLabel(dm, "depth", NULL));
45429566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
45439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4544277ea44aSLisandro Dalcin 
4545e91fa0a1SMatthew G. Knepley   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4546e91fa0a1SMatthew G. Knepley   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4547e91fa0a1SMatthew G. Knepley   else PetscCall(DMPlexStratify_Topological_Private(dm, label));
4548552f7358SJed Brown 
4549bf4602e4SToby Isaac   { /* just in case there is an empty process */
4550bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4551bf4602e4SToby Isaac 
45529566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
4553712fec58SPierre Jolivet     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
455448a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4555bf4602e4SToby Isaac   }
45569566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
45579566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
45583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4559552f7358SJed Brown }
4560552f7358SJed Brown 
4561d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4562d71ae5a4SJacob Faibussowitsch {
4563412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4564412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4565ba2698f1SMatthew G. Knepley 
4566412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
45679566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
45689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
45699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4570ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4571ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4572ba2698f1SMatthew G. Knepley     switch (pdepth) {
4573d71ae5a4SJacob Faibussowitsch     case 0:
4574d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4575d71ae5a4SJacob Faibussowitsch       break;
4576ba2698f1SMatthew G. Knepley     case 1:
4577ba2698f1SMatthew G. Knepley       switch (coneSize) {
4578d71ae5a4SJacob Faibussowitsch       case 2:
4579d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4580d71ae5a4SJacob Faibussowitsch         break;
4581d71ae5a4SJacob Faibussowitsch       case 3:
4582d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4583d71ae5a4SJacob Faibussowitsch         break;
4584ba2698f1SMatthew G. Knepley       case 4:
4585ba2698f1SMatthew G. Knepley         switch (dim) {
4586d71ae5a4SJacob Faibussowitsch         case 2:
4587d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4588d71ae5a4SJacob Faibussowitsch           break;
4589d71ae5a4SJacob Faibussowitsch         case 3:
4590d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4591d71ae5a4SJacob Faibussowitsch           break;
4592d71ae5a4SJacob Faibussowitsch         default:
4593d71ae5a4SJacob Faibussowitsch           break;
4594ba2698f1SMatthew G. Knepley         }
4595ba2698f1SMatthew G. Knepley         break;
4596d71ae5a4SJacob Faibussowitsch       case 5:
4597d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4598d71ae5a4SJacob Faibussowitsch         break;
4599d71ae5a4SJacob Faibussowitsch       case 6:
4600d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4601d71ae5a4SJacob Faibussowitsch         break;
4602d71ae5a4SJacob Faibussowitsch       case 8:
4603d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4604d71ae5a4SJacob Faibussowitsch         break;
4605d71ae5a4SJacob Faibussowitsch       default:
4606d71ae5a4SJacob Faibussowitsch         break;
4607ba2698f1SMatthew G. Knepley       }
4608ba2698f1SMatthew G. Knepley     }
4609ba2698f1SMatthew G. Knepley   } else {
4610ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4611ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4612ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4613ba2698f1SMatthew G. Knepley       switch (dim) {
4614ba2698f1SMatthew G. Knepley       case 1:
4615ba2698f1SMatthew G. Knepley         switch (coneSize) {
4616d71ae5a4SJacob Faibussowitsch         case 2:
4617d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4618d71ae5a4SJacob Faibussowitsch           break;
4619d71ae5a4SJacob Faibussowitsch         default:
4620d71ae5a4SJacob Faibussowitsch           break;
4621ba2698f1SMatthew G. Knepley         }
4622ba2698f1SMatthew G. Knepley         break;
4623ba2698f1SMatthew G. Knepley       case 2:
4624ba2698f1SMatthew G. Knepley         switch (coneSize) {
4625d71ae5a4SJacob Faibussowitsch         case 3:
4626d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4627d71ae5a4SJacob Faibussowitsch           break;
4628d71ae5a4SJacob Faibussowitsch         case 4:
4629d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4630d71ae5a4SJacob Faibussowitsch           break;
4631d71ae5a4SJacob Faibussowitsch         default:
4632d71ae5a4SJacob Faibussowitsch           break;
4633ba2698f1SMatthew G. Knepley         }
4634ba2698f1SMatthew G. Knepley         break;
4635ba2698f1SMatthew G. Knepley       case 3:
4636ba2698f1SMatthew G. Knepley         switch (coneSize) {
4637d71ae5a4SJacob Faibussowitsch         case 4:
4638d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4639d71ae5a4SJacob Faibussowitsch           break;
46409371c9d4SSatish Balay         case 5: {
4641da9060c4SMatthew G. Knepley           const PetscInt *cone;
4642da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4643da9060c4SMatthew G. Knepley 
46449566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
46459566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4646da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4647d71ae5a4SJacob Faibussowitsch           case 3:
4648d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4649d71ae5a4SJacob Faibussowitsch             break;
4650d71ae5a4SJacob Faibussowitsch           case 4:
4651d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4652d71ae5a4SJacob Faibussowitsch             break;
4653da9060c4SMatthew G. Knepley           }
46549371c9d4SSatish Balay         } break;
4655d71ae5a4SJacob Faibussowitsch         case 6:
4656d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4657d71ae5a4SJacob Faibussowitsch           break;
4658d71ae5a4SJacob Faibussowitsch         default:
4659d71ae5a4SJacob Faibussowitsch           break;
4660ba2698f1SMatthew G. Knepley         }
4661ba2698f1SMatthew G. Knepley         break;
4662d71ae5a4SJacob Faibussowitsch       default:
4663d71ae5a4SJacob Faibussowitsch         break;
4664ba2698f1SMatthew G. Knepley       }
4665ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4666ba2698f1SMatthew G. Knepley       switch (coneSize) {
4667d71ae5a4SJacob Faibussowitsch       case 2:
4668d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4669d71ae5a4SJacob Faibussowitsch         break;
4670d71ae5a4SJacob Faibussowitsch       case 3:
4671d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4672d71ae5a4SJacob Faibussowitsch         break;
4673d71ae5a4SJacob Faibussowitsch       case 4:
4674d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4675d71ae5a4SJacob Faibussowitsch         break;
4676d71ae5a4SJacob Faibussowitsch       default:
4677d71ae5a4SJacob Faibussowitsch         break;
4678ba2698f1SMatthew G. Knepley       }
4679ba2698f1SMatthew G. Knepley     }
4680ba2698f1SMatthew G. Knepley   }
4681412e9a14SMatthew G. Knepley   *pt = ct;
46823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4683ba2698f1SMatthew G. Knepley }
4684412e9a14SMatthew G. Knepley 
4685412e9a14SMatthew G. Knepley /*@
4686412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4687412e9a14SMatthew G. Knepley 
468820f4b53cSBarry Smith   Collective
4689412e9a14SMatthew G. Knepley 
4690412e9a14SMatthew G. Knepley   Input Parameter:
469160225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4692412e9a14SMatthew G. Knepley 
4693412e9a14SMatthew G. Knepley   Level: developer
4694412e9a14SMatthew G. Knepley 
4695a1cb98faSBarry Smith   Note:
4696a1cb98faSBarry Smith   This function is normally called automatically when a cell type is requested. It creates an
4697a1cb98faSBarry Smith   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4698a1cb98faSBarry Smith   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4699412e9a14SMatthew G. Knepley 
4700a1cb98faSBarry Smith   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4701a1cb98faSBarry Smith 
47021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4703412e9a14SMatthew G. Knepley @*/
4704d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4705d71ae5a4SJacob Faibussowitsch {
4706412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4707412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4708412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4709412e9a14SMatthew G. Knepley 
4710412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4711412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4712412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
47139566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
47149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
47159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
471621027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
471721027e53SStefano Zampini   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4718412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4719327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4720412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4721412e9a14SMatthew G. Knepley 
47229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
47239566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4724841fc1b7SMatthew 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]);
47259566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4726*6497c311SBarry Smith     mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
4727412e9a14SMatthew G. Knepley   }
47289566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
47299566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
47303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4731ba2698f1SMatthew G. Knepley }
4732ba2698f1SMatthew G. Knepley 
4733552f7358SJed Brown /*@C
4734552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4735552f7358SJed Brown 
4736552f7358SJed Brown   Not Collective
4737552f7358SJed Brown 
4738552f7358SJed Brown   Input Parameters:
4739a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4740552f7358SJed Brown . numPoints - The number of input points for the join
4741552f7358SJed Brown - points    - The input points
4742552f7358SJed Brown 
4743552f7358SJed Brown   Output Parameters:
4744552f7358SJed Brown + numCoveredPoints - The number of points in the join
4745552f7358SJed Brown - coveredPoints    - The points in the join
4746552f7358SJed Brown 
4747552f7358SJed Brown   Level: intermediate
4748552f7358SJed Brown 
4749a1cb98faSBarry Smith   Note:
4750a1cb98faSBarry Smith   Currently, this is restricted to a single level join
4751552f7358SJed Brown 
475260225df5SJacob Faibussowitsch   Fortran Notes:
47532c9a7b26SBarry Smith   `converedPoints` must be declared with
47542c9a7b26SBarry Smith .vb
47552c9a7b26SBarry Smith   PetscInt, pointer :: coveredPints(:)
47562c9a7b26SBarry Smith .ve
47572c9a7b26SBarry Smith 
47582c9a7b26SBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding.
47593813dfbdSMatthew G Knepley 
47601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4761552f7358SJed Brown @*/
47625d83a8b1SBarry Smith PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4763d71ae5a4SJacob Faibussowitsch {
4764552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4765552f7358SJed Brown   PetscInt *join[2];
4766552f7358SJed Brown   PetscInt  joinSize, i = 0;
4767552f7358SJed Brown   PetscInt  dof, off, p, c, m;
47686302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4769552f7358SJed Brown 
4770552f7358SJed Brown   PetscFunctionBegin;
4771552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47724f572ea9SToby Isaac   PetscAssertPointer(points, 3);
47734f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
47744f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
47756302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
47766302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
47776302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4778552f7358SJed Brown   /* Copy in support of first point */
47799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
47809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4781ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4782552f7358SJed Brown   /* Check each successive support */
4783552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4784552f7358SJed Brown     PetscInt newJoinSize = 0;
4785552f7358SJed Brown 
47869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
47879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4788552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4789552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4790552f7358SJed Brown 
4791552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4792552f7358SJed Brown         if (point == join[i][m]) {
4793552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4794552f7358SJed Brown           break;
4795552f7358SJed Brown         }
4796552f7358SJed Brown       }
4797552f7358SJed Brown     }
4798552f7358SJed Brown     joinSize = newJoinSize;
4799552f7358SJed Brown     i        = 1 - i;
4800552f7358SJed Brown   }
4801552f7358SJed Brown   *numCoveredPoints = joinSize;
4802552f7358SJed Brown   *coveredPoints    = join[i];
48036302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
48043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4805552f7358SJed Brown }
4806552f7358SJed Brown 
4807552f7358SJed Brown /*@C
48082c9a7b26SBarry Smith   DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()`
4809552f7358SJed Brown 
4810552f7358SJed Brown   Not Collective
4811552f7358SJed Brown 
4812552f7358SJed Brown   Input Parameters:
4813a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4814552f7358SJed Brown . numPoints - The number of input points for the join
4815552f7358SJed Brown - points    - The input points
4816552f7358SJed Brown 
4817552f7358SJed Brown   Output Parameters:
4818552f7358SJed Brown + numCoveredPoints - The number of points in the join
4819552f7358SJed Brown - coveredPoints    - The points in the join
4820552f7358SJed Brown 
4821552f7358SJed Brown   Level: intermediate
4822552f7358SJed Brown 
482360225df5SJacob Faibussowitsch   Fortran Notes:
482420f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4825a1cb98faSBarry Smith 
48261cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4827552f7358SJed Brown @*/
48282c9a7b26SBarry Smith PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4829d71ae5a4SJacob Faibussowitsch {
4830552f7358SJed Brown   PetscFunctionBegin;
4831552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48324f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
48334f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
48344f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
48359566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4836d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
48373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4838552f7358SJed Brown }
4839552f7358SJed Brown 
4840552f7358SJed Brown /*@C
4841552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4842552f7358SJed Brown 
4843552f7358SJed Brown   Not Collective
4844552f7358SJed Brown 
4845552f7358SJed Brown   Input Parameters:
4846a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4847552f7358SJed Brown . numPoints - The number of input points for the join
48482c9a7b26SBarry Smith - points    - The input points, its length is `numPoints`
4849552f7358SJed Brown 
4850552f7358SJed Brown   Output Parameters:
4851552f7358SJed Brown + numCoveredPoints - The number of points in the join
48522c9a7b26SBarry Smith - coveredPoints    - The points in the join, its length is `numCoveredPoints`
4853552f7358SJed Brown 
4854552f7358SJed Brown   Level: intermediate
4855552f7358SJed Brown 
485660225df5SJacob Faibussowitsch   Fortran Notes:
48572c9a7b26SBarry Smith   `points` and `converedPoints` must be declared with
48582c9a7b26SBarry Smith .vb
48592c9a7b26SBarry Smith   PetscInt, pointer :: points(:)
48602c9a7b26SBarry Smith   PetscInt, pointer :: coveredPints(:)
48612c9a7b26SBarry Smith .ve
48622c9a7b26SBarry Smith 
48632c9a7b26SBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding.
4864a1cb98faSBarry Smith 
48651cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4866552f7358SJed Brown @*/
48675d83a8b1SBarry Smith PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
4868d71ae5a4SJacob Faibussowitsch {
4869552f7358SJed Brown   PetscInt *offsets, **closures;
4870552f7358SJed Brown   PetscInt *join[2];
4871552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
487224c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4873552f7358SJed Brown 
4874552f7358SJed Brown   PetscFunctionBegin;
4875552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48764f572ea9SToby Isaac   PetscAssertPointer(points, 3);
48774f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
48784f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4879552f7358SJed Brown 
48809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
48819566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
48829566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
48836302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
488424c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
48859566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
48869566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4887552f7358SJed Brown 
4888552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4889552f7358SJed Brown     PetscInt closureSize;
4890552f7358SJed Brown 
48919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
48920d644c17SKarl Rupp 
4893552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4894552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4895552f7358SJed Brown       PetscInt pStart, pEnd, i;
4896552f7358SJed Brown 
48979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4898552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4899552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4900552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4901552f7358SJed Brown           break;
4902552f7358SJed Brown         }
4903552f7358SJed Brown       }
4904552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4905552f7358SJed Brown     }
490663a3b9bcSJacob 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);
4907552f7358SJed Brown   }
4908552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4909552f7358SJed Brown     PetscInt dof;
4910552f7358SJed Brown 
4911552f7358SJed Brown     /* Copy in support of first point */
4912552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4913ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4914552f7358SJed Brown     /* Check each successive cone */
4915552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4916552f7358SJed Brown       PetscInt newJoinSize = 0;
4917552f7358SJed Brown 
4918552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
4919552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4920552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
4921552f7358SJed Brown 
4922552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4923552f7358SJed Brown           if (point == join[i][m]) {
4924552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
4925552f7358SJed Brown             break;
4926552f7358SJed Brown           }
4927552f7358SJed Brown         }
4928552f7358SJed Brown       }
4929552f7358SJed Brown       joinSize = newJoinSize;
4930552f7358SJed Brown       i        = 1 - i;
4931552f7358SJed Brown     }
4932552f7358SJed Brown     if (joinSize) break;
4933552f7358SJed Brown   }
4934552f7358SJed Brown   *numCoveredPoints = joinSize;
4935552f7358SJed Brown   *coveredPoints    = join[i];
493648a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
49379566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
49389566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
49396302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
49403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4941552f7358SJed Brown }
4942552f7358SJed Brown 
4943552f7358SJed Brown /*@C
4944552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4945552f7358SJed Brown 
4946552f7358SJed Brown   Not Collective
4947552f7358SJed Brown 
4948552f7358SJed Brown   Input Parameters:
4949a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4950552f7358SJed Brown . numPoints - The number of input points for the meet
49512c9a7b26SBarry Smith - points    - The input points, of length `numPoints`
4952552f7358SJed Brown 
4953552f7358SJed Brown   Output Parameters:
495460225df5SJacob Faibussowitsch + numCoveringPoints - The number of points in the meet
49552c9a7b26SBarry Smith - coveringPoints    - The points in the meet, of length `numCoveringPoints`
4956552f7358SJed Brown 
4957552f7358SJed Brown   Level: intermediate
4958552f7358SJed Brown 
4959a1cb98faSBarry Smith   Note:
4960a1cb98faSBarry Smith   Currently, this is restricted to a single level meet
4961552f7358SJed Brown 
49623813dfbdSMatthew G Knepley   Fortran Notes:
49632c9a7b26SBarry Smith   `coveringPoints` must be declared with
49642c9a7b26SBarry Smith .vb
49652c9a7b26SBarry Smith   PetscInt, pointer :: coveringPoints(:)
49662c9a7b26SBarry Smith .ve
49672c9a7b26SBarry Smith 
496820f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
49693813dfbdSMatthew G Knepley 
49701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4971552f7358SJed Brown @*/
49725d83a8b1SBarry Smith PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[])
4973d71ae5a4SJacob Faibussowitsch {
4974552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4975552f7358SJed Brown   PetscInt *meet[2];
4976552f7358SJed Brown   PetscInt  meetSize, i = 0;
4977552f7358SJed Brown   PetscInt  dof, off, p, c, m;
49786302a7fbSVaclav Hapla   PetscInt  maxConeSize;
4979552f7358SJed Brown 
4980552f7358SJed Brown   PetscFunctionBegin;
4981552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49824f572ea9SToby Isaac   PetscAssertPointer(points, 3);
49834f572ea9SToby Isaac   PetscAssertPointer(numCoveringPoints, 4);
49844f572ea9SToby Isaac   PetscAssertPointer(coveringPoints, 5);
49856302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
49866302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
49876302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4988552f7358SJed Brown   /* Copy in cone of first point */
49899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
49909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4991ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4992552f7358SJed Brown   /* Check each successive cone */
4993552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4994552f7358SJed Brown     PetscInt newMeetSize = 0;
4995552f7358SJed Brown 
49969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
49979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4998552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4999552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
5000552f7358SJed Brown 
5001552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
5002552f7358SJed Brown         if (point == meet[i][m]) {
5003552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
5004552f7358SJed Brown           break;
5005552f7358SJed Brown         }
5006552f7358SJed Brown       }
5007552f7358SJed Brown     }
5008552f7358SJed Brown     meetSize = newMeetSize;
5009552f7358SJed Brown     i        = 1 - i;
5010552f7358SJed Brown   }
5011552f7358SJed Brown   *numCoveringPoints = meetSize;
5012552f7358SJed Brown   *coveringPoints    = meet[i];
50136302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
50143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5015552f7358SJed Brown }
5016552f7358SJed Brown 
5017552f7358SJed Brown /*@C
50182c9a7b26SBarry Smith   DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()`
5019552f7358SJed Brown 
5020552f7358SJed Brown   Not Collective
5021552f7358SJed Brown 
5022552f7358SJed Brown   Input Parameters:
5023a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5024552f7358SJed Brown . numPoints - The number of input points for the meet
5025552f7358SJed Brown - points    - The input points
5026552f7358SJed Brown 
5027552f7358SJed Brown   Output Parameters:
5028552f7358SJed Brown + numCoveredPoints - The number of points in the meet
5029552f7358SJed Brown - coveredPoints    - The points in the meet
5030552f7358SJed Brown 
5031552f7358SJed Brown   Level: intermediate
5032552f7358SJed Brown 
503360225df5SJacob Faibussowitsch   Fortran Notes:
503420f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
50353813dfbdSMatthew G Knepley 
50361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
5037552f7358SJed Brown @*/
50385d83a8b1SBarry Smith PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5039d71ae5a4SJacob Faibussowitsch {
5040552f7358SJed Brown   PetscFunctionBegin;
5041552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50424f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
50434f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
50444f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
50459566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
5046d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
50473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5048552f7358SJed Brown }
5049552f7358SJed Brown 
5050552f7358SJed Brown /*@C
5051552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
5052552f7358SJed Brown 
5053552f7358SJed Brown   Not Collective
5054552f7358SJed Brown 
5055552f7358SJed Brown   Input Parameters:
5056a1cb98faSBarry Smith + dm        - The `DMPLEX` object
5057552f7358SJed Brown . numPoints - The number of input points for the meet
50582c9a7b26SBarry Smith - points    - The input points, of length  `numPoints`
5059552f7358SJed Brown 
5060552f7358SJed Brown   Output Parameters:
5061552f7358SJed Brown + numCoveredPoints - The number of points in the meet
50622c9a7b26SBarry Smith - coveredPoints    - The points in the meet, of length  `numCoveredPoints`
5063552f7358SJed Brown 
5064552f7358SJed Brown   Level: intermediate
5065552f7358SJed Brown 
506660225df5SJacob Faibussowitsch   Fortran Notes:
50672c9a7b26SBarry Smith   `points` and `coveredPoints` must be declared with
50682c9a7b26SBarry Smith .vb
50692c9a7b26SBarry Smith   PetscInt, pointer :: points(:)
50702c9a7b26SBarry Smith   PetscInt, pointer :: coveredPoints(:)
50712c9a7b26SBarry Smith .ve
50722c9a7b26SBarry Smith 
507320f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
50743813dfbdSMatthew G Knepley 
50751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
5076552f7358SJed Brown @*/
50775d83a8b1SBarry Smith PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[])
5078d71ae5a4SJacob Faibussowitsch {
5079552f7358SJed Brown   PetscInt *offsets, **closures;
5080552f7358SJed Brown   PetscInt *meet[2];
5081552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
508224c766afSToby Isaac   PetscInt  p, h, c, m, mc;
5083552f7358SJed Brown 
5084552f7358SJed Brown   PetscFunctionBegin;
5085552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
50864f572ea9SToby Isaac   PetscAssertPointer(points, 3);
50874f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
50884f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
5089552f7358SJed Brown 
50909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
50919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
50929566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
50936302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
509424c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
50959566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
50969566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
5097552f7358SJed Brown 
5098552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
5099552f7358SJed Brown     PetscInt closureSize;
5100552f7358SJed Brown 
51019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
51020d644c17SKarl Rupp 
5103552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
5104552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
5105552f7358SJed Brown       PetscInt pStart, pEnd, i;
5106552f7358SJed Brown 
51079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
5108552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
5109552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
5110552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
5111552f7358SJed Brown           break;
5112552f7358SJed Brown         }
5113552f7358SJed Brown       }
5114552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
5115552f7358SJed Brown     }
511663a3b9bcSJacob 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);
5117552f7358SJed Brown   }
5118552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
5119552f7358SJed Brown     PetscInt dof;
5120552f7358SJed Brown 
5121552f7358SJed Brown     /* Copy in cone of first point */
5122552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
5123ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
5124552f7358SJed Brown     /* Check each successive cone */
5125552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
5126552f7358SJed Brown       PetscInt newMeetSize = 0;
5127552f7358SJed Brown 
5128552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
5129552f7358SJed Brown       for (c = 0; c < dof; ++c) {
5130552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
5131552f7358SJed Brown 
5132552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
5133552f7358SJed Brown           if (point == meet[i][m]) {
5134552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
5135552f7358SJed Brown             break;
5136552f7358SJed Brown           }
5137552f7358SJed Brown         }
5138552f7358SJed Brown       }
5139552f7358SJed Brown       meetSize = newMeetSize;
5140552f7358SJed Brown       i        = 1 - i;
5141552f7358SJed Brown     }
5142552f7358SJed Brown     if (meetSize) break;
5143552f7358SJed Brown   }
5144552f7358SJed Brown   *numCoveredPoints = meetSize;
5145552f7358SJed Brown   *coveredPoints    = meet[i];
514648a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
51479566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
51489566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
51496302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
51503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5151552f7358SJed Brown }
5152552f7358SJed Brown 
5153cc4c1da9SBarry Smith /*@
5154a1cb98faSBarry Smith   DMPlexEqual - Determine if two `DM` have the same topology
51554e3744c5SMatthew G. Knepley 
51564e3744c5SMatthew G. Knepley   Not Collective
51574e3744c5SMatthew G. Knepley 
51584e3744c5SMatthew G. Knepley   Input Parameters:
5159a1cb98faSBarry Smith + dmA - A `DMPLEX` object
5160a1cb98faSBarry Smith - dmB - A `DMPLEX` object
51614e3744c5SMatthew G. Knepley 
51622fe279fdSBarry Smith   Output Parameter:
5163a1cb98faSBarry Smith . equal - `PETSC_TRUE` if the topologies are identical
51644e3744c5SMatthew G. Knepley 
51654e3744c5SMatthew G. Knepley   Level: intermediate
51664e3744c5SMatthew G. Knepley 
5167a1cb98faSBarry Smith   Note:
51683c7db156SBarry Smith   We are not solving graph isomorphism, so we do not permute.
51694e3744c5SMatthew G. Knepley 
51701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
51714e3744c5SMatthew G. Knepley @*/
5172d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5173d71ae5a4SJacob Faibussowitsch {
51744e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
51754e3744c5SMatthew G. Knepley 
51764e3744c5SMatthew G. Knepley   PetscFunctionBegin;
51774e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
51784e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
51794f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
51804e3744c5SMatthew G. Knepley 
51814e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
51829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
51839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
51843ba16761SJacob Faibussowitsch   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
51859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
51869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
51873ba16761SJacob Faibussowitsch   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
51884e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
51894e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
51904e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
51914e3744c5SMatthew G. Knepley 
51929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
51939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
51949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
51959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
51969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
51979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
51983ba16761SJacob Faibussowitsch     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
51994e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
52003ba16761SJacob Faibussowitsch       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
52013ba16761SJacob Faibussowitsch       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
52024e3744c5SMatthew G. Knepley     }
52039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
52049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
52059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
52069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
52073ba16761SJacob Faibussowitsch     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
52084e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
52093ba16761SJacob Faibussowitsch       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
52104e3744c5SMatthew G. Knepley     }
52114e3744c5SMatthew G. Knepley   }
52124e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
52133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52144e3744c5SMatthew G. Knepley }
52154e3744c5SMatthew G. Knepley 
5216cc4c1da9SBarry Smith /*@
52177cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
52187cd05799SMatthew G. Knepley 
52197cd05799SMatthew G. Knepley   Not Collective
52207cd05799SMatthew G. Knepley 
52217cd05799SMatthew G. Knepley   Input Parameters:
5222a1cb98faSBarry Smith + dm         - The `DMPLEX`
52237cd05799SMatthew G. Knepley . cellDim    - The cell dimension
52247cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
52257cd05799SMatthew G. Knepley 
52262fe279fdSBarry Smith   Output Parameter:
52277cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
52287cd05799SMatthew G. Knepley 
52297cd05799SMatthew G. Knepley   Level: developer
52307cd05799SMatthew G. Knepley 
5231a1cb98faSBarry Smith   Note:
52327cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
52337cd05799SMatthew G. Knepley 
52341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
52357cd05799SMatthew G. Knepley @*/
5236d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5237d71ae5a4SJacob Faibussowitsch {
523882f516ccSBarry Smith   MPI_Comm comm;
5239552f7358SJed Brown 
5240552f7358SJed Brown   PetscFunctionBegin;
52419566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
52424f572ea9SToby Isaac   PetscAssertPointer(numFaceVertices, 4);
5243552f7358SJed Brown   switch (cellDim) {
5244d71ae5a4SJacob Faibussowitsch   case 0:
5245d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
5246d71ae5a4SJacob Faibussowitsch     break;
5247d71ae5a4SJacob Faibussowitsch   case 1:
5248d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
5249d71ae5a4SJacob Faibussowitsch     break;
5250552f7358SJed Brown   case 2:
5251552f7358SJed Brown     switch (numCorners) {
525219436ca2SJed Brown     case 3:                 /* triangle */
525319436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5254552f7358SJed Brown       break;
525519436ca2SJed Brown     case 4:                 /* quadrilateral */
525619436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5257552f7358SJed Brown       break;
525819436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
525919436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5260552f7358SJed Brown       break;
526119436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
526219436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5263552f7358SJed Brown       break;
5264d71ae5a4SJacob Faibussowitsch     default:
5265d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5266552f7358SJed Brown     }
5267552f7358SJed Brown     break;
5268552f7358SJed Brown   case 3:
5269552f7358SJed Brown     switch (numCorners) {
527019436ca2SJed Brown     case 4:                 /* tetradehdron */
527119436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
5272552f7358SJed Brown       break;
527319436ca2SJed Brown     case 6:                 /* tet cohesive cells */
527419436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5275552f7358SJed Brown       break;
527619436ca2SJed Brown     case 8:                 /* hexahedron */
527719436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5278552f7358SJed Brown       break;
527919436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
528019436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5281552f7358SJed Brown       break;
528219436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
528319436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5284552f7358SJed Brown       break;
528519436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
528619436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5287552f7358SJed Brown       break;
528819436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
528919436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5290552f7358SJed Brown       break;
529119436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
529219436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
5293552f7358SJed Brown       break;
5294d71ae5a4SJacob Faibussowitsch     default:
5295d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5296552f7358SJed Brown     }
5297552f7358SJed Brown     break;
5298d71ae5a4SJacob Faibussowitsch   default:
5299d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5300552f7358SJed Brown   }
53013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5302552f7358SJed Brown }
5303552f7358SJed Brown 
5304552f7358SJed Brown /*@
5305a1cb98faSBarry Smith   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
5306552f7358SJed Brown 
5307552f7358SJed Brown   Not Collective
5308552f7358SJed Brown 
5309aa50250dSMatthew G. Knepley   Input Parameter:
5310a1cb98faSBarry Smith . dm - The `DMPLEX` object
5311552f7358SJed Brown 
5312aa50250dSMatthew G. Knepley   Output Parameter:
5313a1cb98faSBarry Smith . depthLabel - The `DMLabel` recording point depth
5314552f7358SJed Brown 
5315552f7358SJed Brown   Level: developer
5316552f7358SJed Brown 
53171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5318aa50250dSMatthew G. Knepley @*/
5319d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5320d71ae5a4SJacob Faibussowitsch {
5321aa50250dSMatthew G. Knepley   PetscFunctionBegin;
5322aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53234f572ea9SToby Isaac   PetscAssertPointer(depthLabel, 2);
5324c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
53253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5326aa50250dSMatthew G. Knepley }
5327aa50250dSMatthew G. Knepley 
5328aa50250dSMatthew G. Knepley /*@
5329aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5330aa50250dSMatthew G. Knepley 
5331aa50250dSMatthew G. Knepley   Not Collective
5332aa50250dSMatthew G. Knepley 
5333aa50250dSMatthew G. Knepley   Input Parameter:
5334a1cb98faSBarry Smith . dm - The `DMPLEX` object
5335aa50250dSMatthew G. Knepley 
5336aa50250dSMatthew G. Knepley   Output Parameter:
5337aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
5338aa50250dSMatthew G. Knepley 
5339aa50250dSMatthew G. Knepley   Level: developer
5340552f7358SJed Brown 
5341b1bb481bSMatthew Knepley   Notes:
5342a1cb98faSBarry Smith   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
5343a1cb98faSBarry Smith 
5344a1cb98faSBarry Smith   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
5345a1cb98faSBarry Smith 
5346dc287ab2SVaclav Hapla   An empty mesh gives -1.
5347b1bb481bSMatthew Knepley 
53481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5349552f7358SJed Brown @*/
5350d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5351d71ae5a4SJacob Faibussowitsch {
53529f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5353aa50250dSMatthew G. Knepley   DMLabel  label;
5354452349dbSMatthew G. Knepley   PetscInt d = -1;
5355552f7358SJed Brown 
5356552f7358SJed Brown   PetscFunctionBegin;
5357552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53584f572ea9SToby Isaac   PetscAssertPointer(depth, 2);
53599f4ada15SMatthew G. Knepley   if (mesh->tr) {
53609f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
53619f4ada15SMatthew G. Knepley   } else {
53629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
5363452349dbSMatthew G. Knepley     // Allow missing depths
5364452349dbSMatthew G. Knepley     if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d));
5365452349dbSMatthew G. Knepley     *depth = d;
53669f4ada15SMatthew G. Knepley   }
53673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5368552f7358SJed Brown }
5369552f7358SJed Brown 
5370552f7358SJed Brown /*@
537120f4b53cSBarry Smith   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5372552f7358SJed Brown 
5373552f7358SJed Brown   Not Collective
5374552f7358SJed Brown 
5375552f7358SJed Brown   Input Parameters:
5376a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5377570fa34dSVaclav Hapla - depth - The requested depth
5378552f7358SJed Brown 
5379552f7358SJed Brown   Output Parameters:
538020f4b53cSBarry Smith + start - The first point at this `depth`
538120f4b53cSBarry Smith - end   - One beyond the last point at this `depth`
5382552f7358SJed Brown 
5383552f7358SJed Brown   Level: developer
5384552f7358SJed Brown 
5385a1cb98faSBarry Smith   Notes:
5386a1cb98faSBarry Smith   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5387a1cb98faSBarry Smith   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5388a1cb98faSBarry Smith   higher dimension, e.g., "edges".
5389a1cb98faSBarry Smith 
53902827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5391552f7358SJed Brown @*/
5392d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5393d71ae5a4SJacob Faibussowitsch {
53949f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5395aa50250dSMatthew G. Knepley   DMLabel  label;
539663d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
5397552f7358SJed Brown 
5398552f7358SJed Brown   PetscFunctionBegin;
5399552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54009371c9d4SSatish Balay   if (start) {
54014f572ea9SToby Isaac     PetscAssertPointer(start, 3);
54029371c9d4SSatish Balay     *start = 0;
54039371c9d4SSatish Balay   }
54049371c9d4SSatish Balay   if (end) {
54054f572ea9SToby Isaac     PetscAssertPointer(end, 4);
54069371c9d4SSatish Balay     *end = 0;
54079371c9d4SSatish Balay   }
54089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
54093ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5410570fa34dSVaclav Hapla   if (depth < 0) {
541163d1a920SMatthew G. Knepley     if (start) *start = pStart;
541263d1a920SMatthew G. Knepley     if (end) *end = pEnd;
54133ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5414552f7358SJed Brown   }
54159f4ada15SMatthew G. Knepley   if (mesh->tr) {
54169f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
54179f4ada15SMatthew G. Knepley   } else {
54189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
541928b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5420570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
54219f4ada15SMatthew G. Knepley   }
54223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5423552f7358SJed Brown }
5424552f7358SJed Brown 
5425552f7358SJed Brown /*@
542620f4b53cSBarry Smith   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5427552f7358SJed Brown 
5428552f7358SJed Brown   Not Collective
5429552f7358SJed Brown 
5430552f7358SJed Brown   Input Parameters:
5431a1cb98faSBarry Smith + dm     - The `DMPLEX` object
5432570fa34dSVaclav Hapla - height - The requested height
5433552f7358SJed Brown 
5434552f7358SJed Brown   Output Parameters:
543520f4b53cSBarry Smith + start - The first point at this `height`
543620f4b53cSBarry Smith - end   - One beyond the last point at this `height`
5437552f7358SJed Brown 
5438552f7358SJed Brown   Level: developer
5439552f7358SJed Brown 
5440a1cb98faSBarry Smith   Notes:
5441a1cb98faSBarry Smith   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5442a1cb98faSBarry Smith   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5443a1cb98faSBarry Smith   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5444a1cb98faSBarry Smith 
54452827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5446552f7358SJed Brown @*/
5447d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5448d71ae5a4SJacob Faibussowitsch {
5449aa50250dSMatthew G. Knepley   DMLabel  label;
545063d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5451552f7358SJed Brown 
5452552f7358SJed Brown   PetscFunctionBegin;
5453552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54549371c9d4SSatish Balay   if (start) {
54554f572ea9SToby Isaac     PetscAssertPointer(start, 3);
54569371c9d4SSatish Balay     *start = 0;
54579371c9d4SSatish Balay   }
54589371c9d4SSatish Balay   if (end) {
54594f572ea9SToby Isaac     PetscAssertPointer(end, 4);
54609371c9d4SSatish Balay     *end = 0;
54619371c9d4SSatish Balay   }
54629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
54633ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5464570fa34dSVaclav Hapla   if (height < 0) {
546563d1a920SMatthew G. Knepley     if (start) *start = pStart;
546663d1a920SMatthew G. Knepley     if (end) *end = pEnd;
54673ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5468552f7358SJed Brown   }
54699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
547059e4dc13SStefano Zampini   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
547159e4dc13SStefano Zampini   else PetscCall(DMGetDimension(dm, &depth));
547259e4dc13SStefano Zampini   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
547359e4dc13SStefano Zampini   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
54743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5475552f7358SJed Brown }
5476552f7358SJed Brown 
5477ba2698f1SMatthew G. Knepley /*@
547820f4b53cSBarry Smith   DMPlexGetPointDepth - Get the `depth` of a given point
5479ba2698f1SMatthew G. Knepley 
5480ba2698f1SMatthew G. Knepley   Not Collective
5481ba2698f1SMatthew G. Knepley 
5482d8d19677SJose E. Roman   Input Parameters:
5483a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5484ba2698f1SMatthew G. Knepley - point - The point
5485ba2698f1SMatthew G. Knepley 
5486ba2698f1SMatthew G. Knepley   Output Parameter:
548720f4b53cSBarry Smith . depth - The depth of the `point`
5488ba2698f1SMatthew G. Knepley 
5489ba2698f1SMatthew G. Knepley   Level: intermediate
5490ba2698f1SMatthew G. Knepley 
54911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5492ba2698f1SMatthew G. Knepley @*/
5493d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5494d71ae5a4SJacob Faibussowitsch {
5495ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5496ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54974f572ea9SToby Isaac   PetscAssertPointer(depth, 3);
54989566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
54993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5500ba2698f1SMatthew G. Knepley }
5501ba2698f1SMatthew G. Knepley 
5502ba2698f1SMatthew G. Knepley /*@
550320f4b53cSBarry Smith   DMPlexGetPointHeight - Get the `height` of a given point
55040c0a32dcSVaclav Hapla 
55050c0a32dcSVaclav Hapla   Not Collective
55060c0a32dcSVaclav Hapla 
5507d8d19677SJose E. Roman   Input Parameters:
5508a1cb98faSBarry Smith + dm    - The `DMPLEX` object
55090c0a32dcSVaclav Hapla - point - The point
55100c0a32dcSVaclav Hapla 
55110c0a32dcSVaclav Hapla   Output Parameter:
551220f4b53cSBarry Smith . height - The height of the `point`
55130c0a32dcSVaclav Hapla 
55140c0a32dcSVaclav Hapla   Level: intermediate
55150c0a32dcSVaclav Hapla 
55161cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
55170c0a32dcSVaclav Hapla @*/
5518d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5519d71ae5a4SJacob Faibussowitsch {
55200c0a32dcSVaclav Hapla   PetscInt n, pDepth;
55210c0a32dcSVaclav Hapla 
55220c0a32dcSVaclav Hapla   PetscFunctionBegin;
55230c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55244f572ea9SToby Isaac   PetscAssertPointer(height, 3);
55259566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
55269566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
55270c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
55283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55290c0a32dcSVaclav Hapla }
55300c0a32dcSVaclav Hapla 
55310c0a32dcSVaclav Hapla /*@
5532a1cb98faSBarry Smith   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5533ba2698f1SMatthew G. Knepley 
5534ba2698f1SMatthew G. Knepley   Not Collective
5535ba2698f1SMatthew G. Knepley 
5536ba2698f1SMatthew G. Knepley   Input Parameter:
5537a1cb98faSBarry Smith . dm - The `DMPLEX` object
5538ba2698f1SMatthew G. Knepley 
5539ba2698f1SMatthew G. Knepley   Output Parameter:
5540a1cb98faSBarry Smith . celltypeLabel - The `DMLabel` recording cell polytope type
5541412e9a14SMatthew G. Knepley 
5542ba2698f1SMatthew G. Knepley   Level: developer
5543ba2698f1SMatthew G. Knepley 
5544a1cb98faSBarry Smith   Note:
5545a1cb98faSBarry Smith   This function will trigger automatica computation of cell types. This can be disabled by calling
5546a1cb98faSBarry Smith   `DMCreateLabel`(dm, "celltype") beforehand.
5547a1cb98faSBarry Smith 
55481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5549ba2698f1SMatthew G. Knepley @*/
5550d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5551d71ae5a4SJacob Faibussowitsch {
5552ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5553ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55544f572ea9SToby Isaac   PetscAssertPointer(celltypeLabel, 2);
55559566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5556ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
55573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5558ba2698f1SMatthew G. Knepley }
5559ba2698f1SMatthew G. Knepley 
5560ba2698f1SMatthew G. Knepley /*@
5561ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5562ba2698f1SMatthew G. Knepley 
5563ba2698f1SMatthew G. Knepley   Not Collective
5564ba2698f1SMatthew G. Knepley 
5565d8d19677SJose E. Roman   Input Parameters:
5566a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5567ba2698f1SMatthew G. Knepley - cell - The cell
5568ba2698f1SMatthew G. Knepley 
5569ba2698f1SMatthew G. Knepley   Output Parameter:
5570ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5571ba2698f1SMatthew G. Knepley 
5572ba2698f1SMatthew G. Knepley   Level: intermediate
5573ba2698f1SMatthew G. Knepley 
55741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5575ba2698f1SMatthew G. Knepley @*/
5576d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5577d71ae5a4SJacob Faibussowitsch {
55789f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5579ba2698f1SMatthew G. Knepley   DMLabel  label;
5580ba2698f1SMatthew G. Knepley   PetscInt ct;
5581ba2698f1SMatthew G. Knepley 
5582ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5583ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55844f572ea9SToby Isaac   PetscAssertPointer(celltype, 3);
55859f4ada15SMatthew G. Knepley   if (mesh->tr) {
55869f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
55879f4ada15SMatthew G. Knepley   } else {
558821027e53SStefano Zampini     PetscInt pStart, pEnd;
558921027e53SStefano Zampini 
559021027e53SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
559121027e53SStefano Zampini     if (!mesh->cellTypes) { /* XXX remove? optimize? */
559221027e53SStefano Zampini       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
559321027e53SStefano Zampini       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
559421027e53SStefano Zampini       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
559521027e53SStefano Zampini       for (PetscInt p = pStart; p < pEnd; p++) {
559621027e53SStefano Zampini         PetscCall(DMLabelGetValue(label, p, &ct));
5597*6497c311SBarry Smith         mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct;
559821027e53SStefano Zampini       }
559921027e53SStefano Zampini     }
560021027e53SStefano Zampini     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
560121027e53SStefano Zampini     if (PetscDefined(USE_DEBUG)) {
56029566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
56039566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, cell, &ct));
560463a3b9bcSJacob Faibussowitsch       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5605936381afSPierre Jolivet       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
560621027e53SStefano Zampini     }
56079f4ada15SMatthew G. Knepley   }
56083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5609ba2698f1SMatthew G. Knepley }
5610ba2698f1SMatthew G. Knepley 
5611412e9a14SMatthew G. Knepley /*@
5612412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5613412e9a14SMatthew G. Knepley 
5614412e9a14SMatthew G. Knepley   Not Collective
5615412e9a14SMatthew G. Knepley 
5616412e9a14SMatthew G. Knepley   Input Parameters:
5617a1cb98faSBarry Smith + dm       - The `DMPLEX` object
5618412e9a14SMatthew G. Knepley . cell     - The cell
5619412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5620412e9a14SMatthew G. Knepley 
5621a1cb98faSBarry Smith   Level: advanced
5622a1cb98faSBarry Smith 
5623a1cb98faSBarry Smith   Note:
5624a1cb98faSBarry Smith   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5625412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5626412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5627db485b19SStefano Zampini   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5628412e9a14SMatthew G. Knepley 
56291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5630412e9a14SMatthew G. Knepley @*/
5631d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5632d71ae5a4SJacob Faibussowitsch {
563321027e53SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
5634412e9a14SMatthew G. Knepley   DMLabel  label;
563521027e53SStefano Zampini   PetscInt pStart, pEnd;
5636412e9a14SMatthew G. Knepley 
5637412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5638412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
563921027e53SStefano Zampini   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
56409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
56419566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
564221027e53SStefano Zampini   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5643*6497c311SBarry Smith   mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype;
56443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5645412e9a14SMatthew G. Knepley }
5646412e9a14SMatthew G. Knepley 
5647d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5648d71ae5a4SJacob Faibussowitsch {
5649c789d87fSToby Isaac   PetscSection section;
56503e922f36SToby Isaac   PetscInt     maxHeight;
5651dd4c3f67SMatthew G. Knepley   const char  *prefix;
5652552f7358SJed Brown 
5653552f7358SJed Brown   PetscFunctionBegin;
56549566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
5655dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5656dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5657dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
56589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
56599566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
56609566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
56619566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
56629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
56638f4c458bSMatthew G. Knepley 
56649566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
56659566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5666dd4c3f67SMatthew G. Knepley   (*cdm)->cloneOpts = PETSC_TRUE;
5667dd4c3f67SMatthew G. Knepley   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
56683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5669552f7358SJed Brown }
5670552f7358SJed Brown 
5671d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5672d71ae5a4SJacob Faibussowitsch {
56736858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
56746858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5675f19dbd58SToby Isaac 
5676f19dbd58SToby Isaac   PetscFunctionBegin;
5677f19dbd58SToby Isaac   *field = NULL;
56789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
56799566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
56806858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
56816858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5682f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
56836858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
56846858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5685f19dbd58SToby Isaac   }
56863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5687f19dbd58SToby Isaac }
5688f19dbd58SToby Isaac 
5689cc4c1da9SBarry Smith /*@
56907cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
56917cd05799SMatthew G. Knepley 
56927cd05799SMatthew G. Knepley   Not Collective
56937cd05799SMatthew G. Knepley 
56942fe279fdSBarry Smith   Input Parameter:
5695a1cb98faSBarry Smith . dm - The `DMPLEX` object
56967cd05799SMatthew G. Knepley 
56977cd05799SMatthew G. Knepley   Output Parameter:
5698a1cb98faSBarry Smith . section - The `PetscSection` object
56997cd05799SMatthew G. Knepley 
57007cd05799SMatthew G. Knepley   Level: developer
57017cd05799SMatthew G. Knepley 
57021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
57037cd05799SMatthew G. Knepley @*/
5704d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5705d71ae5a4SJacob Faibussowitsch {
5706552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5707552f7358SJed Brown 
5708552f7358SJed Brown   PetscFunctionBegin;
5709552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5710552f7358SJed Brown   if (section) *section = mesh->coneSection;
57113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5712552f7358SJed Brown }
5713552f7358SJed Brown 
5714cc4c1da9SBarry Smith /*@
57157cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
57167cd05799SMatthew G. Knepley 
57177cd05799SMatthew G. Knepley   Not Collective
57187cd05799SMatthew G. Knepley 
57192fe279fdSBarry Smith   Input Parameter:
5720a1cb98faSBarry Smith . dm - The `DMPLEX` object
57217cd05799SMatthew G. Knepley 
57227cd05799SMatthew G. Knepley   Output Parameter:
5723a1cb98faSBarry Smith . section - The `PetscSection` object
57247cd05799SMatthew G. Knepley 
57257cd05799SMatthew G. Knepley   Level: developer
57267cd05799SMatthew G. Knepley 
57271cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
57287cd05799SMatthew G. Knepley @*/
5729d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5730d71ae5a4SJacob Faibussowitsch {
57318cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
57328cb4d582SMatthew G. Knepley 
57338cb4d582SMatthew G. Knepley   PetscFunctionBegin;
57348cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
57358cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
57363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57378cb4d582SMatthew G. Knepley }
57388cb4d582SMatthew G. Knepley 
57397cd05799SMatthew G. Knepley /*@C
57407cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
57417cd05799SMatthew G. Knepley 
57427cd05799SMatthew G. Knepley   Not Collective
57437cd05799SMatthew G. Knepley 
57442fe279fdSBarry Smith   Input Parameter:
5745a1cb98faSBarry Smith . dm - The `DMPLEX` object
57467cd05799SMatthew G. Knepley 
57477cd05799SMatthew G. Knepley   Output Parameter:
57487cd05799SMatthew G. Knepley . cones - The cone for each point
57497cd05799SMatthew G. Knepley 
57507cd05799SMatthew G. Knepley   Level: developer
57517cd05799SMatthew G. Knepley 
57521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
57537cd05799SMatthew G. Knepley @*/
5754d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5755d71ae5a4SJacob Faibussowitsch {
5756552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5757552f7358SJed Brown 
5758552f7358SJed Brown   PetscFunctionBegin;
5759552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5760552f7358SJed Brown   if (cones) *cones = mesh->cones;
57613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5762552f7358SJed Brown }
5763552f7358SJed Brown 
57647cd05799SMatthew G. Knepley /*@C
57657cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
57667cd05799SMatthew G. Knepley 
57677cd05799SMatthew G. Knepley   Not Collective
57687cd05799SMatthew G. Knepley 
57692fe279fdSBarry Smith   Input Parameter:
5770a1cb98faSBarry Smith . dm - The `DMPLEX` object
57717cd05799SMatthew G. Knepley 
57727cd05799SMatthew G. Knepley   Output Parameter:
5773b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
57747cd05799SMatthew G. Knepley 
57757cd05799SMatthew G. Knepley   Level: developer
57767cd05799SMatthew G. Knepley 
5777b5a892a1SMatthew G. Knepley   Notes:
57782c9a7b26SBarry Smith   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points
57792c9a7b26SBarry Smith   as returned by `DMPlexGetConeOrientation()`.
5780b5a892a1SMatthew G. Knepley 
5781a1cb98faSBarry Smith   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5782b5a892a1SMatthew G. Knepley 
57831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
57847cd05799SMatthew G. Knepley @*/
5785d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5786d71ae5a4SJacob Faibussowitsch {
5787552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5788552f7358SJed Brown 
5789552f7358SJed Brown   PetscFunctionBegin;
5790552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5791552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
57923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5793552f7358SJed Brown }
5794552f7358SJed Brown 
57954ee01570SBarry Smith /* FEM Support */
5796552f7358SJed Brown 
5797d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5798d2b2dc1eSMatthew G. Knepley {
5799d2b2dc1eSMatthew G. Knepley   PetscInt depth;
5800d2b2dc1eSMatthew G. Knepley 
5801d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
5802d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
5803d2b2dc1eSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5804d2b2dc1eSMatthew G. Knepley   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5805d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
5806d2b2dc1eSMatthew G. Knepley }
5807d2b2dc1eSMatthew G. Knepley 
58085962854dSMatthew G. Knepley PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
58095962854dSMatthew G. Knepley {
58105962854dSMatthew G. Knepley   PetscInt depth;
58115962854dSMatthew G. Knepley 
58125962854dSMatthew G. Knepley   PetscFunctionBegin;
58135962854dSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
58145962854dSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
58155962854dSMatthew G. Knepley   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
58165962854dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
58175962854dSMatthew G. Knepley }
58185962854dSMatthew G. Knepley 
58199e8305c2SJed Brown /*
58209e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
58219e8305c2SJed Brown  representing a line in the section.
58229e8305c2SJed Brown */
58235f82726aSMatthew G. Knepley static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5824d71ae5a4SJacob Faibussowitsch {
5825e327e467SRezgar Shakeri   PetscObject  obj;
5826e327e467SRezgar Shakeri   PetscClassId id;
5827e327e467SRezgar Shakeri   PetscFE      fe = NULL;
5828e327e467SRezgar Shakeri 
58299e8305c2SJed Brown   PetscFunctionBeginHot;
58309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5831e327e467SRezgar Shakeri   PetscCall(DMGetField(dm, field, NULL, &obj));
5832e327e467SRezgar Shakeri   PetscCall(PetscObjectGetClassId(obj, &id));
5833e327e467SRezgar Shakeri   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;
5834e327e467SRezgar Shakeri 
5835e327e467SRezgar Shakeri   if (!fe) {
5836e327e467SRezgar Shakeri     /* Assume the full interpolated mesh is in the chart; lines in particular */
58379e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
58389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
58399e8305c2SJed Brown     *k = *k / *Nc + 1;
5840e327e467SRezgar Shakeri   } else {
5841e327e467SRezgar Shakeri     PetscInt       dual_space_size, dim;
58425f82726aSMatthew G. Knepley     PetscDualSpace dsp;
58435f82726aSMatthew G. Knepley 
5844e327e467SRezgar Shakeri     PetscCall(DMGetDimension(dm, &dim));
58455f82726aSMatthew G. Knepley     PetscCall(PetscFEGetDualSpace(fe, &dsp));
58465f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5847e327e467SRezgar Shakeri     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
58485f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
58495f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
58505f82726aSMatthew G. Knepley   }
58515f82726aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
58525f82726aSMatthew G. Knepley }
58535f82726aSMatthew G. Knepley 
58545f82726aSMatthew G. Knepley static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
58555f82726aSMatthew G. Knepley {
58565f82726aSMatthew G. Knepley   PetscFunctionBeginHot;
58575f82726aSMatthew G. Knepley   if (tensor) {
58585f82726aSMatthew G. Knepley     *dof = PetscPowInt(k + 1, dim);
58595f82726aSMatthew G. Knepley   } else {
58605f82726aSMatthew G. Knepley     switch (dim) {
58615f82726aSMatthew G. Knepley     case 1:
58625f82726aSMatthew G. Knepley       *dof = k + 1;
58635f82726aSMatthew G. Knepley       break;
58645f82726aSMatthew G. Knepley     case 2:
58655f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2)) / 2;
58665f82726aSMatthew G. Knepley       break;
58675f82726aSMatthew G. Knepley     case 3:
58685f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
58695f82726aSMatthew G. Knepley       break;
58705f82726aSMatthew G. Knepley     default:
58715f82726aSMatthew G. Knepley       *dof = 0;
58725f82726aSMatthew G. Knepley     }
58739e8305c2SJed Brown   }
58743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58759e8305c2SJed Brown }
58769e8305c2SJed Brown 
5877a4355906SMatthew Knepley /*@
5878bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5879bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
588020f4b53cSBarry Smith   section provided (or the section of the `DM`).
5881a4355906SMatthew Knepley 
5882a4355906SMatthew Knepley   Input Parameters:
588320f4b53cSBarry Smith + dm      - The `DM`
588420f4b53cSBarry Smith . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
588520f4b53cSBarry Smith - section - The `PetscSection` to reorder, or `NULL` for the default section
5886a4355906SMatthew Knepley 
5887bc1eb3faSJed Brown   Example:
5888bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5889bc1eb3faSJed Brown .vb
5890bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5891bc1eb3faSJed Brown 
5892bc1eb3faSJed Brown   v4 -- e6 -- v3
5893bc1eb3faSJed Brown   |           |
5894bc1eb3faSJed Brown   e7    c0    e8
5895bc1eb3faSJed Brown   |           |
5896bc1eb3faSJed Brown   v1 -- e5 -- v2
5897bc1eb3faSJed Brown .ve
5898bc1eb3faSJed Brown 
5899bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5900bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5901bc1eb3faSJed Brown .vb
5902bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5903bc1eb3faSJed Brown     v1 -> [4]
5904bc1eb3faSJed Brown     ...
5905bc1eb3faSJed Brown     e5 -> [8, 9]
5906bc1eb3faSJed Brown .ve
5907bc1eb3faSJed Brown 
5908bc1eb3faSJed Brown   which corresponds to the dofs
5909bc1eb3faSJed Brown .vb
5910bc1eb3faSJed Brown     6   10  11  7
5911bc1eb3faSJed Brown     13  2   3   15
5912bc1eb3faSJed Brown     12  0   1   14
5913bc1eb3faSJed Brown     4   8   9   5
5914bc1eb3faSJed Brown .ve
5915bc1eb3faSJed Brown 
5916bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5917bc1eb3faSJed Brown .vb
5918bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5919bc1eb3faSJed Brown .ve
5920bc1eb3faSJed Brown 
5921bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5922bc1eb3faSJed Brown .vb
5923bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5924bc1eb3faSJed Brown .ve
5925bc1eb3faSJed Brown 
5926a4355906SMatthew Knepley   Level: developer
5927a4355906SMatthew Knepley 
5928da9ac489SAlbert Cowie   Notes:
5929a1cb98faSBarry Smith   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5930a1cb98faSBarry Smith   degree of the basis.
5931a1cb98faSBarry Smith 
5932da9ac489SAlbert Cowie   This is required to run with libCEED.
5933da9ac489SAlbert Cowie 
59341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5935a4355906SMatthew Knepley @*/
5936d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5937d71ae5a4SJacob Faibussowitsch {
59387391a63aSMatthew G. Knepley   DMLabel   label;
5939bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
59405f82726aSMatthew G. Knepley   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;
59413194fc30SMatthew G. Knepley 
59423194fc30SMatthew G. Knepley   PetscFunctionBegin;
59439566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
59443ba16761SJacob Faibussowitsch   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5945a433471fSStefano Zampini   if (point < 0) {
5946a433471fSStefano Zampini     PetscInt sStart, sEnd;
5947a433471fSStefano Zampini 
59489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5949a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
5950a433471fSStefano Zampini   }
59519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
59529566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
59539566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
59549371c9d4SSatish Balay   if (depth == 1) {
59559371c9d4SSatish Balay     eStart = point;
59569371c9d4SSatish Balay   } else if (depth == dim) {
59577391a63aSMatthew G. Knepley     const PetscInt *cone;
59587391a63aSMatthew G. Knepley 
59599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5960d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5961d4e6627bSStefano Zampini     else if (dim == 3) {
5962d4e6627bSStefano Zampini       const PetscInt *cone2;
59639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5964d4e6627bSStefano Zampini       eStart = cone2[0];
596563a3b9bcSJacob 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);
596663a3b9bcSJacob 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);
5967e327e467SRezgar Shakeri 
59689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5969bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
5970bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5971bb197d40SJed Brown     PetscInt *perm;
5972bb197d40SJed Brown 
59733194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
59745f82726aSMatthew G. Knepley       PetscInt dof;
59755f82726aSMatthew G. Knepley 
59765f82726aSMatthew G. Knepley       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
59775f82726aSMatthew 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);
59785f82726aSMatthew G. Knepley       if (!continuous && d < dim) continue;
59795f82726aSMatthew G. Knepley       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
59805f82726aSMatthew G. Knepley       size += dof * Nc;
59813194fc30SMatthew G. Knepley     }
59829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
59833194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5984bb197d40SJed Brown       switch (d) {
5985babf31e0SJed Brown       case 1:
59865f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
59875f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
5988babf31e0SJed Brown         /*
5989babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5990babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5991babf31e0SJed Brown          */
5992e327e467SRezgar Shakeri         if (continuous) {
5993babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
59949371c9d4SSatish Balay           for (i = 0; i < k - 1; i++)
59959371c9d4SSatish Balay             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5996babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5997babf31e0SJed Brown           foffset = offset;
5998e327e467SRezgar Shakeri         } else {
59995f82726aSMatthew G. Knepley           PetscInt dof;
60005f82726aSMatthew G. Knepley 
60015f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
60025f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
60035f82726aSMatthew G. Knepley           foffset = offset;
6004e327e467SRezgar Shakeri         }
6005babf31e0SJed Brown         break;
600689eabcffSMatthew G. Knepley       case 2:
60073194fc30SMatthew 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} */
60085f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
60095f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
60103194fc30SMatthew G. Knepley         /* The SEM order is
60113194fc30SMatthew G. Knepley 
60123194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
601389eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
60143194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
60153194fc30SMatthew G. Knepley          */
6016e327e467SRezgar Shakeri         if (continuous) {
60173194fc30SMatthew G. Knepley           const PetscInt of   = 0;
60183194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
60193194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
60203194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
60213194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
60223194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
60233194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
60243194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
60253194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
60263194fc30SMatthew G. Knepley           PetscInt       o;
60273194fc30SMatthew G. Knepley 
60283194fc30SMatthew G. Knepley           /* bottom */
60293194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
60309371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
60319371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
60323194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
60333194fc30SMatthew G. Knepley           /* middle */
60343194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
60353194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
60369371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
60379371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
60383194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
60393194fc30SMatthew G. Knepley           }
60403194fc30SMatthew G. Knepley           /* top */
60413194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
60429371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
60439371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
60443194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
60453194fc30SMatthew G. Knepley           foffset = offset;
6046e327e467SRezgar Shakeri         } else {
60475f82726aSMatthew G. Knepley           PetscInt dof;
60485f82726aSMatthew G. Knepley 
60495f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
60505f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
60515f82726aSMatthew G. Knepley           foffset = offset;
60523194fc30SMatthew G. Knepley         }
605389eabcffSMatthew G. Knepley         break;
605489eabcffSMatthew G. Knepley       case 3:
605589eabcffSMatthew G. Knepley         /* The original hex closure is
605689eabcffSMatthew G. Knepley 
605789eabcffSMatthew G. Knepley          {c,
605889eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
605989eabcffSMatthew 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,
606089eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
606189eabcffSMatthew G. Knepley          */
60625f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
60635f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
606489eabcffSMatthew G. Knepley         /* The SEM order is
606589eabcffSMatthew G. Knepley          Bottom Slice
606689eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
606789eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
606889eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
606989eabcffSMatthew G. Knepley 
607089eabcffSMatthew G. Knepley          Middle Slice (j)
607189eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
607289eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
607389eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
607489eabcffSMatthew G. Knepley 
607589eabcffSMatthew G. Knepley          Top Slice
607689eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
607789eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
607889eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
607989eabcffSMatthew G. Knepley          */
6080e327e467SRezgar Shakeri         if (continuous) {
608189eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
608289eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
608389eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
608489eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
608589eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
608689eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
608789eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
608889eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
608989eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
609089eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
609189eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
609289eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
609389eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
609489eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
609589eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
609689eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
609789eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
609889eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
609989eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
610089eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
610189eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
610289eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
610389eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
610489eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
610589eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
610689eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
610789eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
610889eabcffSMatthew G. Knepley           PetscInt       o, n;
610989eabcffSMatthew G. Knepley 
611089eabcffSMatthew G. Knepley           /* Bottom Slice */
611189eabcffSMatthew G. Knepley           /*   bottom */
611289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
61139371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
61149371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
611589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
611689eabcffSMatthew G. Knepley           /*   middle */
611789eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
611889eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
61199371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
61209371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
61219371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
61229371c9d4SSatish Balay             }
612389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
61243194fc30SMatthew G. Knepley           }
612589eabcffSMatthew G. Knepley           /*   top */
612689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
61279371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
61289371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
612989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
613089eabcffSMatthew G. Knepley 
613189eabcffSMatthew G. Knepley           /* Middle Slice */
613289eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
613389eabcffSMatthew G. Knepley             /*   bottom */
613489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
61359371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
61369371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
613789eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
613889eabcffSMatthew G. Knepley             /*   middle */
613989eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
614089eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
61419371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
61429371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
614389eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
614489eabcffSMatthew G. Knepley             }
614589eabcffSMatthew G. Knepley             /*   top */
614689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
61479371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
61489371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
614989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
615089eabcffSMatthew G. Knepley           }
615189eabcffSMatthew G. Knepley 
615289eabcffSMatthew G. Knepley           /* Top Slice */
615389eabcffSMatthew G. Knepley           /*   bottom */
615489eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
61559371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
61569371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
615789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
615889eabcffSMatthew G. Knepley           /*   middle */
615989eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
616089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
61619371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
61629371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
616389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
616489eabcffSMatthew G. Knepley           }
616589eabcffSMatthew G. Knepley           /*   top */
616689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
61679371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
61689371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
616989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
617089eabcffSMatthew G. Knepley 
617189eabcffSMatthew G. Knepley           foffset = offset;
6172e327e467SRezgar Shakeri         } else {
61735f82726aSMatthew G. Knepley           PetscInt dof;
61745f82726aSMatthew G. Knepley 
61755f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
61765f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
61775f82726aSMatthew G. Knepley           foffset = offset;
617889eabcffSMatthew G. Knepley         }
617989eabcffSMatthew G. Knepley         break;
6180d71ae5a4SJacob Faibussowitsch       default:
6181d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
618289eabcffSMatthew G. Knepley       }
618389eabcffSMatthew G. Knepley     }
618463a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
61853194fc30SMatthew G. Knepley     /* Check permutation */
61863194fc30SMatthew G. Knepley     {
61873194fc30SMatthew G. Knepley       PetscInt *check;
61883194fc30SMatthew G. Knepley 
61899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
61901dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
61911dca8a05SBarry Smith         check[i] = -1;
61921dca8a05SBarry 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]);
61931dca8a05SBarry Smith       }
61943194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
61951dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
61969566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
61973194fc30SMatthew G. Knepley     }
61989566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6199a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6200a05c9aa3SJed Brown       PetscInt *loc_perm;
62019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6202a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
6203a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
6204a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
6205a05c9aa3SJed Brown       }
62069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6207a05c9aa3SJed Brown     }
6208bb197d40SJed Brown   }
62093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62103194fc30SMatthew G. Knepley }
62113194fc30SMatthew G. Knepley 
6212d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6213d71ae5a4SJacob Faibussowitsch {
6214e071409bSToby Isaac   PetscDS  prob;
6215e071409bSToby Isaac   PetscInt depth, Nf, h;
6216e071409bSToby Isaac   DMLabel  label;
6217e071409bSToby Isaac 
6218e071409bSToby Isaac   PetscFunctionBeginHot;
62199566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
6220e071409bSToby Isaac   Nf      = prob->Nf;
6221e071409bSToby Isaac   label   = dm->depthLabel;
6222e071409bSToby Isaac   *dspace = NULL;
6223e071409bSToby Isaac   if (field < Nf) {
6224e071409bSToby Isaac     PetscObject disc = prob->disc[field];
6225e071409bSToby Isaac 
6226e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
6227e071409bSToby Isaac       PetscDualSpace dsp;
6228e071409bSToby Isaac 
62299566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
62309566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
62319566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
6232e071409bSToby Isaac       h = depth - 1 - h;
6233e071409bSToby Isaac       if (h) {
62349566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6235e071409bSToby Isaac       } else {
6236e071409bSToby Isaac         *dspace = dsp;
6237e071409bSToby Isaac       }
6238e071409bSToby Isaac     }
6239e071409bSToby Isaac   }
62403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6241e071409bSToby Isaac }
6242e071409bSToby Isaac 
6243d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6244d71ae5a4SJacob Faibussowitsch {
624528351e22SJed Brown   PetscScalar       *array;
624628351e22SJed Brown   const PetscScalar *vArray;
6247d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
62481a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
6249552f7358SJed Brown 
62501b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
62519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
62529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
62539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
62549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
62553f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
62569df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
62579df71ca4SMatthew G. Knepley       PetscInt dof;
6258d9917b9dSMatthew G. Knepley 
62599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
62609df71ca4SMatthew G. Knepley       size += dof;
62619df71ca4SMatthew G. Knepley     }
62629df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
62639df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
62642a3aaacfSMatthew G. Knepley       PetscInt       dof;
62655a1bb5cfSMatthew G. Knepley 
62665a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
62679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
62685a1bb5cfSMatthew G. Knepley       size += dof;
62695a1bb5cfSMatthew G. Knepley     }
62703f7cbbe7SMatthew G. Knepley     if (!values) {
62713f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
62723ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
62733f7cbbe7SMatthew G. Knepley     }
62749566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6275982e9ed1SMatthew G. Knepley   } else {
6276982e9ed1SMatthew G. Knepley     array = *values;
6277982e9ed1SMatthew G. Knepley   }
62789df71ca4SMatthew G. Knepley   size = 0;
627928351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
62809df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
62819df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
628228351e22SJed Brown     const PetscScalar *varr;
6283d9917b9dSMatthew G. Knepley 
62849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
62859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
62868e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
6287ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
62889df71ca4SMatthew G. Knepley     size += dof;
62899df71ca4SMatthew G. Knepley   }
62909df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
62919df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
62929df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
62935a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
629428351e22SJed Brown     const PetscScalar *varr;
62955a1bb5cfSMatthew G. Knepley 
629652ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
62979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
62989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
62998e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
63005a1bb5cfSMatthew G. Knepley     if (o >= 0) {
6301ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
63025a1bb5cfSMatthew G. Knepley     } else {
6303ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
63045a1bb5cfSMatthew G. Knepley     }
63059df71ca4SMatthew G. Knepley     size += dof;
63065a1bb5cfSMatthew G. Knepley   }
630728351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
63089df71ca4SMatthew G. Knepley   if (!*values) {
63095a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
63105a1bb5cfSMatthew G. Knepley     *values = array;
63119df71ca4SMatthew G. Knepley   } else {
631263a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
63138c312ff3SMatthew G. Knepley     *csize = size;
63149df71ca4SMatthew G. Knepley   }
63153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63165a1bb5cfSMatthew G. Knepley }
6317d9917b9dSMatthew G. Knepley 
631827f02ce8SMatthew G. Knepley /* Compress out points not in the section */
6319d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6320d71ae5a4SJacob Faibussowitsch {
632127f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
632227f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
632327f02ce8SMatthew G. Knepley 
63249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
632527f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
632627f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
632727f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
632827f02ce8SMatthew G. Knepley       points[q * 2]     = r;
632927f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
633027f02ce8SMatthew G. Knepley       ++q;
633127f02ce8SMatthew G. Knepley     }
633227f02ce8SMatthew G. Knepley   }
633327f02ce8SMatthew G. Knepley   *numPoints = q;
63343ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
633527f02ce8SMatthew G. Knepley }
633627f02ce8SMatthew G. Knepley 
633797529cf3SJed Brown /* Compressed closure does not apply closure permutation */
633807218a29SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6339d71ae5a4SJacob Faibussowitsch {
634027f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
6341923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
6342923c78e0SToby Isaac 
6343923c78e0SToby Isaac   PetscFunctionBeginHot;
63449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
634507218a29SMatthew G. Knepley   if (!ornt && *clPoints) {
6346923c78e0SToby Isaac     PetscInt dof, off;
6347923c78e0SToby Isaac 
63489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
63499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
63509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
6351923c78e0SToby Isaac     np  = dof / 2;
63528e3a54c0SPierre Jolivet     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
635327f02ce8SMatthew G. Knepley   } else {
635407218a29SMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
63559566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
6356923c78e0SToby Isaac   }
6357923c78e0SToby Isaac   *numPoints = np;
6358923c78e0SToby Isaac   *points    = pts;
6359923c78e0SToby Isaac   *clp       = cla;
63603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6361923c78e0SToby Isaac }
6362923c78e0SToby Isaac 
6363d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6364d71ae5a4SJacob Faibussowitsch {
6365923c78e0SToby Isaac   PetscFunctionBeginHot;
6366923c78e0SToby Isaac   if (!*clPoints) {
63679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6368923c78e0SToby Isaac   } else {
63699566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
6370923c78e0SToby Isaac   }
6371923c78e0SToby Isaac   *numPoints = 0;
6372923c78e0SToby Isaac   *points    = NULL;
6373923c78e0SToby Isaac   *clSec     = NULL;
6374923c78e0SToby Isaac   *clPoints  = NULL;
6375923c78e0SToby Isaac   *clp       = NULL;
63763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6377923c78e0SToby Isaac }
6378923c78e0SToby Isaac 
6379d71ae5a4SJacob 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[])
6380d71ae5a4SJacob Faibussowitsch {
63811a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
638297e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
638397e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
63841a271a75SMatthew G. Knepley 
63851a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6386fe02ba77SJed Brown   *size = 0;
63879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
638897e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
638997e99dd9SToby Isaac     const PetscInt     point = points[2 * p];
639097e99dd9SToby Isaac     const PetscInt    *perm  = perms ? perms[p] : NULL;
639197e99dd9SToby Isaac     const PetscScalar *flip  = flips ? flips[p] : NULL;
63921a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
63931a271a75SMatthew G. Knepley     const PetscScalar *varr;
63941a271a75SMatthew G. Knepley 
63959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
63969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
63978e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
639897e99dd9SToby Isaac     if (clperm) {
639997e99dd9SToby Isaac       if (perm) {
640097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
64011a271a75SMatthew G. Knepley       } else {
640297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
640397e99dd9SToby Isaac       }
640497e99dd9SToby Isaac       if (flip) {
640597e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
640697e99dd9SToby Isaac       }
640797e99dd9SToby Isaac     } else {
640897e99dd9SToby Isaac       if (perm) {
640997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
641097e99dd9SToby Isaac       } else {
641197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
641297e99dd9SToby Isaac       }
641397e99dd9SToby Isaac       if (flip) {
641497e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
64151a271a75SMatthew G. Knepley       }
64161a271a75SMatthew G. Knepley     }
641797e99dd9SToby Isaac     offset += dof;
641897e99dd9SToby Isaac   }
64199566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
64201a271a75SMatthew G. Knepley   *size = offset;
64213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64221a271a75SMatthew G. Knepley }
64231a271a75SMatthew G. Knepley 
6424d71ae5a4SJacob 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[])
6425d71ae5a4SJacob Faibussowitsch {
64261a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
64271a271a75SMatthew G. Knepley 
64281a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6429fe02ba77SJed Brown   *size = 0;
64301a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
643197e99dd9SToby Isaac     PetscInt            p;
643297e99dd9SToby Isaac     const PetscInt    **perms = NULL;
643397e99dd9SToby Isaac     const PetscScalar **flips = NULL;
64341a271a75SMatthew G. Knepley 
64359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
643697e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
643797e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
643897e99dd9SToby Isaac       PetscInt           fdof, foff, b;
64391a271a75SMatthew G. Knepley       const PetscScalar *varr;
644097e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
644197e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
64421a271a75SMatthew G. Knepley 
64439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
64449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
64451a271a75SMatthew G. Knepley       varr = &vArray[foff];
644697e99dd9SToby Isaac       if (clperm) {
64479371c9d4SSatish Balay         if (perm) {
6448ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
64491a271a75SMatthew G. Knepley         } else {
6450ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
64519371c9d4SSatish Balay         }
64529371c9d4SSatish Balay         if (flip) {
6453ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
64549371c9d4SSatish Balay         }
64559371c9d4SSatish Balay       } else {
64569371c9d4SSatish Balay         if (perm) {
6457ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
64589371c9d4SSatish Balay         } else {
6459ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
64609371c9d4SSatish Balay         }
64619371c9d4SSatish Balay         if (flip) {
6462ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
64639371c9d4SSatish Balay         }
64641a271a75SMatthew G. Knepley       }
646597e99dd9SToby Isaac       offset += fdof;
64661a271a75SMatthew G. Knepley     }
64679566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
64681a271a75SMatthew G. Knepley   }
64691a271a75SMatthew G. Knepley   *size = offset;
64703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64711a271a75SMatthew G. Knepley }
64721a271a75SMatthew G. Knepley 
6473e8e188d2SZach Atkins PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
647407218a29SMatthew G. Knepley {
647507218a29SMatthew G. Knepley   PetscSection    clSection;
647607218a29SMatthew G. Knepley   IS              clPoints;
647707218a29SMatthew G. Knepley   PetscInt       *points = NULL;
6478e8e188d2SZach Atkins   const PetscInt *clp, *perm = NULL;
647907218a29SMatthew G. Knepley   PetscInt        depth, numFields, numPoints, asize;
648007218a29SMatthew G. Knepley 
648107218a29SMatthew G. Knepley   PetscFunctionBeginHot;
648207218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
648307218a29SMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
648407218a29SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6485e8e188d2SZach Atkins   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
648607218a29SMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
648707218a29SMatthew G. Knepley   PetscCall(PetscSectionGetNumFields(section, &numFields));
648807218a29SMatthew G. Knepley   if (depth == 1 && numFields < 2) {
648907218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
649007218a29SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
649107218a29SMatthew G. Knepley   }
649207218a29SMatthew G. Knepley   /* Get points */
649307218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
649407218a29SMatthew G. Knepley   /* Get sizes */
649507218a29SMatthew G. Knepley   asize = 0;
649607218a29SMatthew G. Knepley   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
649707218a29SMatthew G. Knepley     PetscInt dof;
649807218a29SMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, points[p], &dof));
649907218a29SMatthew G. Knepley     asize += dof;
650007218a29SMatthew G. Knepley   }
650107218a29SMatthew G. Knepley   if (values) {
650207218a29SMatthew G. Knepley     const PetscScalar *vArray;
650307218a29SMatthew G. Knepley     PetscInt           size;
650407218a29SMatthew G. Knepley 
650507218a29SMatthew G. Knepley     if (*values) {
650607218a29SMatthew 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);
650707218a29SMatthew G. Knepley     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6508e8e188d2SZach Atkins     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
650907218a29SMatthew G. Knepley     PetscCall(VecGetArrayRead(v, &vArray));
651007218a29SMatthew G. Knepley     /* Get values */
651107218a29SMatthew G. Knepley     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
651207218a29SMatthew G. Knepley     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
651307218a29SMatthew 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);
651407218a29SMatthew G. Knepley     /* Cleanup array */
651507218a29SMatthew G. Knepley     PetscCall(VecRestoreArrayRead(v, &vArray));
651607218a29SMatthew G. Knepley   }
651707218a29SMatthew G. Knepley   if (csize) *csize = asize;
651807218a29SMatthew G. Knepley   /* Cleanup points */
651907218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
652007218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
652107218a29SMatthew G. Knepley }
652207218a29SMatthew G. Knepley 
6523552f7358SJed Brown /*@C
6524552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6525552f7358SJed Brown 
6526552f7358SJed Brown   Not collective
6527552f7358SJed Brown 
6528552f7358SJed Brown   Input Parameters:
6529a1cb98faSBarry Smith + dm      - The `DM`
653020f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6531552f7358SJed Brown . v       - The local vector
6532a1cb98faSBarry Smith - point   - The point in the `DM`
6533552f7358SJed Brown 
65346b867d5aSJose E. Roman   Input/Output Parameters:
653520f4b53cSBarry Smith + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
65362c9a7b26SBarry Smith - values - An array to use for the values, or *values = `NULL` to have it allocated automatically;
65372c9a7b26SBarry Smith            if the user provided `NULL`, it is a borrowed array and should not be freed, use  `DMPlexVecRestoreClosure()` to return it
653822c1ee49SMatthew G. Knepley 
6539552f7358SJed Brown   Level: intermediate
6540552f7358SJed Brown 
6541a1cb98faSBarry Smith   Notes:
654220f4b53cSBarry Smith   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6543a1cb98faSBarry Smith   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6544a1cb98faSBarry Smith   assembly function, and a user may already have allocated storage for this operation.
6545a1cb98faSBarry Smith 
6546a1cb98faSBarry Smith   A typical use could be
6547a1cb98faSBarry Smith .vb
6548a1cb98faSBarry Smith    values = NULL;
6549a1cb98faSBarry Smith    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6550a1cb98faSBarry Smith    for (cl = 0; cl < clSize; ++cl) {
6551a1cb98faSBarry Smith      <Compute on closure>
6552a1cb98faSBarry Smith    }
6553a1cb98faSBarry Smith    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6554a1cb98faSBarry Smith .ve
6555a1cb98faSBarry Smith   or
6556a1cb98faSBarry Smith .vb
6557a1cb98faSBarry Smith    PetscMalloc1(clMaxSize, &values);
6558a1cb98faSBarry Smith    for (p = pStart; p < pEnd; ++p) {
6559a1cb98faSBarry Smith      clSize = clMaxSize;
6560a1cb98faSBarry Smith      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6561a1cb98faSBarry Smith      for (cl = 0; cl < clSize; ++cl) {
6562a1cb98faSBarry Smith        <Compute on closure>
6563a1cb98faSBarry Smith      }
6564a1cb98faSBarry Smith    }
6565a1cb98faSBarry Smith    PetscFree(values);
6566a1cb98faSBarry Smith .ve
6567a1cb98faSBarry Smith 
656860225df5SJacob Faibussowitsch   Fortran Notes:
65692c9a7b26SBarry Smith   The `csize` argument is not present in the Fortran binding.
6570a1cb98faSBarry Smith 
6571f13dfd9eSBarry Smith   `values` must be declared with
6572f13dfd9eSBarry Smith .vb
6573f13dfd9eSBarry Smith   PetscScalar,dimension(:),pointer   :: values
6574f13dfd9eSBarry Smith .ve
6575f13dfd9eSBarry Smith   and it will be allocated internally by PETSc to hold the values returned
6576f13dfd9eSBarry Smith 
65771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6578552f7358SJed Brown @*/
6579d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6580d71ae5a4SJacob Faibussowitsch {
6581d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
6582e8e188d2SZach Atkins   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
65833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6584552f7358SJed Brown }
6585552f7358SJed Brown 
6586d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6587d71ae5a4SJacob Faibussowitsch {
6588e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6589e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6590e5c487bfSMatthew G. Knepley   IS                 clPoints;
6591e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6592e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6593e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6594c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6595c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6596e5c487bfSMatthew G. Knepley 
6597e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6598e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
65999566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6600e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6601e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
66029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
66039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
66049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6605e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
66069566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
66073ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6608e5c487bfSMatthew G. Knepley   }
6609e5c487bfSMatthew G. Knepley   /* Get points */
661007218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6611c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6612c459fbc1SJed Brown     PetscInt dof;
66139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6614c459fbc1SJed Brown     clsize += dof;
6615c459fbc1SJed Brown   }
66169566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6617e5c487bfSMatthew G. Knepley   /* Filter points */
6618e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6619e5c487bfSMatthew G. Knepley     PetscInt dep;
6620e5c487bfSMatthew G. Knepley 
66219566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6622e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6623e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6624e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6625e5c487bfSMatthew G. Knepley     ++Np;
6626e5c487bfSMatthew G. Knepley   }
6627e5c487bfSMatthew G. Knepley   /* Get array */
6628e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6629e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6630e5c487bfSMatthew G. Knepley 
6631e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
66329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6633e5c487bfSMatthew G. Knepley       asize += dof;
6634e5c487bfSMatthew G. Knepley     }
6635e5c487bfSMatthew G. Knepley     if (!values) {
66369566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6637e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
66383ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
6639e5c487bfSMatthew G. Knepley     }
66409566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6641e5c487bfSMatthew G. Knepley   } else {
6642e5c487bfSMatthew G. Knepley     array = *values;
6643e5c487bfSMatthew G. Knepley   }
66449566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6645e5c487bfSMatthew G. Knepley   /* Get values */
66469566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
66479566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6648e5c487bfSMatthew G. Knepley   /* Cleanup points */
66499566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6650e5c487bfSMatthew G. Knepley   /* Cleanup array */
66519566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6652e5c487bfSMatthew G. Knepley   if (!*values) {
6653e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6654e5c487bfSMatthew G. Knepley     *values = array;
6655e5c487bfSMatthew G. Knepley   } else {
665663a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6657e5c487bfSMatthew G. Knepley     *csize = size;
6658e5c487bfSMatthew G. Knepley   }
66593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6660e5c487bfSMatthew G. Knepley }
6661e5c487bfSMatthew G. Knepley 
6662552f7358SJed Brown /*@C
6663f13dfd9eSBarry Smith   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()`
6664552f7358SJed Brown 
6665552f7358SJed Brown   Not collective
6666552f7358SJed Brown 
6667552f7358SJed Brown   Input Parameters:
6668a1cb98faSBarry Smith + dm      - The `DM`
666920f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6670552f7358SJed Brown . v       - The local vector
6671a1cb98faSBarry Smith . point   - The point in the `DM`
667220f4b53cSBarry Smith . csize   - The number of values in the closure, or `NULL`
6673f13dfd9eSBarry Smith - values  - The array of values
6674552f7358SJed Brown 
6675552f7358SJed Brown   Level: intermediate
6676552f7358SJed Brown 
6677a1cb98faSBarry Smith   Note:
667820f4b53cSBarry Smith   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6679a1cb98faSBarry Smith 
6680f13dfd9eSBarry Smith   Fortran Note:
668120f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6682a1cb98faSBarry Smith 
66831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6684552f7358SJed Brown @*/
6685d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6686d71ae5a4SJacob Faibussowitsch {
6687552f7358SJed Brown   PetscInt size = 0;
6688552f7358SJed Brown 
6689552f7358SJed Brown   PetscFunctionBegin;
6690552f7358SJed Brown   /* Should work without recalculating size */
66919566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6692c9fdaa05SMatthew G. Knepley   *values = NULL;
66933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6694552f7358SJed Brown }
6695552f7358SJed Brown 
6696d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6697d71ae5a4SJacob Faibussowitsch {
66989371c9d4SSatish Balay   *x += y;
66999371c9d4SSatish Balay }
6700d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6701d71ae5a4SJacob Faibussowitsch {
67029371c9d4SSatish Balay   *x = y;
67039371c9d4SSatish Balay }
6704552f7358SJed Brown 
6705d71ae5a4SJacob 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[])
6706d71ae5a4SJacob Faibussowitsch {
6707552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6708552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6709552f7358SJed Brown   PetscScalar    *a;
6710552f7358SJed Brown   PetscInt        off, cind = 0, k;
6711552f7358SJed Brown 
6712552f7358SJed Brown   PetscFunctionBegin;
67139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
67149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6715552f7358SJed Brown   a = &array[off];
6716552f7358SJed Brown   if (!cdof || setBC) {
671797e99dd9SToby Isaac     if (clperm) {
67189371c9d4SSatish Balay       if (perm) {
6719ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6720552f7358SJed Brown       } else {
6721ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
67229371c9d4SSatish Balay       }
67239371c9d4SSatish Balay     } else {
67249371c9d4SSatish Balay       if (perm) {
6725ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
67269371c9d4SSatish Balay       } else {
6727ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
67289371c9d4SSatish Balay       }
6729552f7358SJed Brown     }
6730552f7358SJed Brown   } else {
67319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
673297e99dd9SToby Isaac     if (clperm) {
67339371c9d4SSatish Balay       if (perm) {
67349371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
67359371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
67369371c9d4SSatish Balay             ++cind;
67379371c9d4SSatish Balay             continue;
67389371c9d4SSatish Balay           }
673997e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6740552f7358SJed Brown         }
6741552f7358SJed Brown       } else {
6742552f7358SJed Brown         for (k = 0; k < dof; ++k) {
67439371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
67449371c9d4SSatish Balay             ++cind;
67459371c9d4SSatish Balay             continue;
67469371c9d4SSatish Balay           }
674797e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
674897e99dd9SToby Isaac         }
674997e99dd9SToby Isaac       }
675097e99dd9SToby Isaac     } else {
675197e99dd9SToby Isaac       if (perm) {
675297e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
67539371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
67549371c9d4SSatish Balay             ++cind;
67559371c9d4SSatish Balay             continue;
67569371c9d4SSatish Balay           }
675797e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
675897e99dd9SToby Isaac         }
675997e99dd9SToby Isaac       } else {
676097e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
67619371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
67629371c9d4SSatish Balay             ++cind;
67639371c9d4SSatish Balay             continue;
67649371c9d4SSatish Balay           }
676597e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
676697e99dd9SToby Isaac         }
6767552f7358SJed Brown       }
6768552f7358SJed Brown     }
6769552f7358SJed Brown   }
67703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6771552f7358SJed Brown }
6772552f7358SJed Brown 
6773d71ae5a4SJacob 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[])
6774d71ae5a4SJacob Faibussowitsch {
6775a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6776a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6777a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6778a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6779a5e93ea8SMatthew G. Knepley 
6780a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
67819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
67829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6783a5e93ea8SMatthew G. Knepley   a = &array[off];
6784a5e93ea8SMatthew G. Knepley   if (cdof) {
67859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
678697e99dd9SToby Isaac     if (clperm) {
678797e99dd9SToby Isaac       if (perm) {
6788a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6789a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
679097e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
679197e99dd9SToby Isaac             cind++;
6792a5e93ea8SMatthew G. Knepley           }
6793a5e93ea8SMatthew G. Knepley         }
6794a5e93ea8SMatthew G. Knepley       } else {
6795a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6796a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
679797e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
679897e99dd9SToby Isaac             cind++;
679997e99dd9SToby Isaac           }
680097e99dd9SToby Isaac         }
680197e99dd9SToby Isaac       }
680297e99dd9SToby Isaac     } else {
680397e99dd9SToby Isaac       if (perm) {
680497e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
680597e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
680697e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
680797e99dd9SToby Isaac             cind++;
680897e99dd9SToby Isaac           }
680997e99dd9SToby Isaac         }
681097e99dd9SToby Isaac       } else {
681197e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
681297e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
681397e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
681497e99dd9SToby Isaac             cind++;
681597e99dd9SToby Isaac           }
6816a5e93ea8SMatthew G. Knepley         }
6817a5e93ea8SMatthew G. Knepley       }
6818a5e93ea8SMatthew G. Knepley     }
6819a5e93ea8SMatthew G. Knepley   }
68203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6821a5e93ea8SMatthew G. Knepley }
6822a5e93ea8SMatthew G. Knepley 
6823d71ae5a4SJacob 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[])
6824d71ae5a4SJacob Faibussowitsch {
6825552f7358SJed Brown   PetscScalar    *a;
68261a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
68271a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
682897e99dd9SToby Isaac   PetscInt        cind = 0, b;
6829552f7358SJed Brown 
6830552f7358SJed Brown   PetscFunctionBegin;
68319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
68329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
68339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
68341a271a75SMatthew G. Knepley   a = &array[foff];
6835552f7358SJed Brown   if (!fcdof || setBC) {
683697e99dd9SToby Isaac     if (clperm) {
68379371c9d4SSatish Balay       if (perm) {
6838ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6839552f7358SJed Brown       } else {
6840ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
68419371c9d4SSatish Balay       }
68429371c9d4SSatish Balay     } else {
68439371c9d4SSatish Balay       if (perm) {
6844ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
68459371c9d4SSatish Balay       } else {
6846ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
68479371c9d4SSatish Balay       }
6848552f7358SJed Brown     }
6849552f7358SJed Brown   } else {
68509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
685197e99dd9SToby Isaac     if (clperm) {
685297e99dd9SToby Isaac       if (perm) {
685397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
68549371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
68559371c9d4SSatish Balay             ++cind;
68569371c9d4SSatish Balay             continue;
68579371c9d4SSatish Balay           }
685897e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6859552f7358SJed Brown         }
6860552f7358SJed Brown       } else {
686197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
68629371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
68639371c9d4SSatish Balay             ++cind;
68649371c9d4SSatish Balay             continue;
68659371c9d4SSatish Balay           }
686697e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
686797e99dd9SToby Isaac         }
686897e99dd9SToby Isaac       }
686997e99dd9SToby Isaac     } else {
687097e99dd9SToby Isaac       if (perm) {
687197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
68729371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
68739371c9d4SSatish Balay             ++cind;
68749371c9d4SSatish Balay             continue;
68759371c9d4SSatish Balay           }
687697e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
687797e99dd9SToby Isaac         }
687897e99dd9SToby Isaac       } else {
687997e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
68809371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
68819371c9d4SSatish Balay             ++cind;
68829371c9d4SSatish Balay             continue;
68839371c9d4SSatish Balay           }
688497e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6885552f7358SJed Brown         }
6886552f7358SJed Brown       }
6887552f7358SJed Brown     }
6888552f7358SJed Brown   }
68891a271a75SMatthew G. Knepley   *offset += fdof;
68903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6891552f7358SJed Brown }
6892552f7358SJed Brown 
6893d71ae5a4SJacob 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[])
6894d71ae5a4SJacob Faibussowitsch {
6895a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
68961a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
68971a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
68985da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6899ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6900a5e93ea8SMatthew G. Knepley 
6901a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
69029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
69039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
69049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
69059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
69061a271a75SMatthew G. Knepley   a = &array[foff];
6907a5e93ea8SMatthew G. Knepley   if (fcdof) {
6908ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
69099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
691097e99dd9SToby Isaac     if (clperm) {
691197e99dd9SToby Isaac       if (perm) {
6912ba322698SMatthew G. Knepley         if (comps) {
6913ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6914ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
69159371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
69169371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
69179371c9d4SSatish Balay               ncSet = PETSC_TRUE;
69189371c9d4SSatish Balay             }
69199371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
69209371c9d4SSatish Balay               ++cind;
69219371c9d4SSatish Balay               fcSet = PETSC_TRUE;
69229371c9d4SSatish Balay             }
6923ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6924ba322698SMatthew G. Knepley           }
6925ba322698SMatthew G. Knepley         } else {
692697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
692797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
692897e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6929a5e93ea8SMatthew G. Knepley               ++cind;
6930a5e93ea8SMatthew G. Knepley             }
6931a5e93ea8SMatthew G. Knepley           }
6932ba322698SMatthew G. Knepley         }
6933ba322698SMatthew G. Knepley       } else {
6934ba322698SMatthew G. Knepley         if (comps) {
6935ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6936ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
69379371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
69389371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
69399371c9d4SSatish Balay               ncSet = PETSC_TRUE;
69409371c9d4SSatish Balay             }
69419371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
69429371c9d4SSatish Balay               ++cind;
69439371c9d4SSatish Balay               fcSet = PETSC_TRUE;
69449371c9d4SSatish Balay             }
6945ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6946ba322698SMatthew G. Knepley           }
6947a5e93ea8SMatthew G. Knepley         } else {
694897e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
694997e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
695097e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
695197e99dd9SToby Isaac               ++cind;
695297e99dd9SToby Isaac             }
695397e99dd9SToby Isaac           }
695497e99dd9SToby Isaac         }
6955ba322698SMatthew G. Knepley       }
695697e99dd9SToby Isaac     } else {
695797e99dd9SToby Isaac       if (perm) {
6958ba322698SMatthew G. Knepley         if (comps) {
6959ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6960ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
69619371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
69629371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
69639371c9d4SSatish Balay               ncSet = PETSC_TRUE;
69649371c9d4SSatish Balay             }
69659371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
69669371c9d4SSatish Balay               ++cind;
69679371c9d4SSatish Balay               fcSet = PETSC_TRUE;
69689371c9d4SSatish Balay             }
6969ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6970ba322698SMatthew G. Knepley           }
6971ba322698SMatthew G. Knepley         } else {
697297e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
697397e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
697497e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
697597e99dd9SToby Isaac               ++cind;
697697e99dd9SToby Isaac             }
697797e99dd9SToby Isaac           }
6978ba322698SMatthew G. Knepley         }
6979ba322698SMatthew G. Knepley       } else {
6980ba322698SMatthew G. Knepley         if (comps) {
6981ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6982ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
69839371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
69849371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
69859371c9d4SSatish Balay               ncSet = PETSC_TRUE;
69869371c9d4SSatish Balay             }
69879371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
69889371c9d4SSatish Balay               ++cind;
69899371c9d4SSatish Balay               fcSet = PETSC_TRUE;
69909371c9d4SSatish Balay             }
6991ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6992ba322698SMatthew G. Knepley           }
699397e99dd9SToby Isaac         } else {
699497e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
699597e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
699697e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6997a5e93ea8SMatthew G. Knepley               ++cind;
6998a5e93ea8SMatthew G. Knepley             }
6999a5e93ea8SMatthew G. Knepley           }
7000a5e93ea8SMatthew G. Knepley         }
7001a5e93ea8SMatthew G. Knepley       }
7002a5e93ea8SMatthew G. Knepley     }
7003ba322698SMatthew G. Knepley   }
70041a271a75SMatthew G. Knepley   *offset += fdof;
70053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7006a5e93ea8SMatthew G. Knepley }
7007a5e93ea8SMatthew G. Knepley 
7008d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7009d71ae5a4SJacob Faibussowitsch {
7010552f7358SJed Brown   PetscScalar    *array;
70111b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
70121b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
7013552f7358SJed Brown 
70141b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
70159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
70169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
70179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
70189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
70199566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7020b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
7021b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
7022b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
7023b6ebb6e6SMatthew G. Knepley 
70249371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
70259371c9d4SSatish Balay       dof = 0;
70269371c9d4SSatish Balay       continue;
70279371c9d4SSatish Balay     }
70289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
7029b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
7030b6ebb6e6SMatthew G. Knepley     {
7031b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7032b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
7033b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
7034b6ebb6e6SMatthew G. Knepley 
70359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
70369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
7037b6ebb6e6SMatthew G. Knepley       a = &array[coff];
7038b6ebb6e6SMatthew G. Knepley       if (!cdof) {
7039b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
7040ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
7041b6ebb6e6SMatthew G. Knepley         } else {
7042ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
7043b6ebb6e6SMatthew G. Knepley         }
7044b6ebb6e6SMatthew G. Knepley       } else {
70459566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
7046b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
7047b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
70489371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
70499371c9d4SSatish Balay               ++cind;
70509371c9d4SSatish Balay               continue;
70519371c9d4SSatish Balay             }
7052b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
7053b6ebb6e6SMatthew G. Knepley           }
7054b6ebb6e6SMatthew G. Knepley         } else {
7055b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
70569371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
70579371c9d4SSatish Balay               ++cind;
70589371c9d4SSatish Balay               continue;
70599371c9d4SSatish Balay             }
7060b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
7061b6ebb6e6SMatthew G. Knepley           }
7062b6ebb6e6SMatthew G. Knepley         }
7063b6ebb6e6SMatthew G. Knepley       }
7064b6ebb6e6SMatthew G. Knepley     }
7065b6ebb6e6SMatthew G. Knepley   }
70669566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
70673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7068b6ebb6e6SMatthew G. Knepley }
70691b406b76SMatthew G. Knepley 
70701b406b76SMatthew G. Knepley /*@C
707120f4b53cSBarry Smith   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
70721b406b76SMatthew G. Knepley 
70731b406b76SMatthew G. Knepley   Not collective
70741b406b76SMatthew G. Knepley 
70751b406b76SMatthew G. Knepley   Input Parameters:
7076a1cb98faSBarry Smith + dm      - The `DM`
707720f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
70781b406b76SMatthew G. Knepley . v       - The local vector
707920f4b53cSBarry Smith . point   - The point in the `DM`
70801b406b76SMatthew G. Knepley . values  - The array of values
7081a1cb98faSBarry Smith - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
7082a1cb98faSBarry Smith             where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
70831b406b76SMatthew G. Knepley 
70841b406b76SMatthew G. Knepley   Level: intermediate
70851b406b76SMatthew G. Knepley 
7086f13dfd9eSBarry Smith   Note:
7087f13dfd9eSBarry Smith   Usually the input arrays were obtained with `DMPlexVecGetClosure()`
7088f13dfd9eSBarry Smith 
7089f13dfd9eSBarry Smith   Fortran Note:
7090f13dfd9eSBarry Smith   `values` must be declared with
7091f13dfd9eSBarry Smith .vb
7092f13dfd9eSBarry Smith   PetscScalar,dimension(:),pointer   :: values
7093f13dfd9eSBarry Smith .ve
7094f13dfd9eSBarry Smith 
70951cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
70961b406b76SMatthew G. Knepley @*/
7097d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7098d71ae5a4SJacob Faibussowitsch {
70991b406b76SMatthew G. Knepley   PetscSection    clSection;
71001b406b76SMatthew G. Knepley   IS              clPoints;
71011b406b76SMatthew G. Knepley   PetscScalar    *array;
71021b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
710327f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
7104c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
71051b406b76SMatthew G. Knepley 
71061a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
71071b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
71089566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
71091a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
71101a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
71119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
71129566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
71131b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
71149566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
71153ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
71161b406b76SMatthew G. Knepley   }
71171a271a75SMatthew G. Knepley   /* Get points */
711807218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7119c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
7120c459fbc1SJed Brown     PetscInt dof;
71219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7122c459fbc1SJed Brown     clsize += dof;
7123c459fbc1SJed Brown   }
71249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
71251a271a75SMatthew G. Knepley   /* Get array */
71269566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
71271a271a75SMatthew G. Knepley   /* Get values */
7128ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
712997e99dd9SToby Isaac     PetscInt offset = 0, f;
7130552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
713197e99dd9SToby Isaac       const PetscInt    **perms = NULL;
713297e99dd9SToby Isaac       const PetscScalar **flips = NULL;
713397e99dd9SToby Isaac 
71349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7135552f7358SJed Brown       switch (mode) {
7136552f7358SJed Brown       case INSERT_VALUES:
713797e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
713897e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
713997e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
714097e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
71413ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
71429371c9d4SSatish Balay         }
71439371c9d4SSatish Balay         break;
7144552f7358SJed Brown       case INSERT_ALL_VALUES:
714597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
714697e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
714797e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
714897e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
71493ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
71509371c9d4SSatish Balay         }
71519371c9d4SSatish Balay         break;
7152a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
715397e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
715497e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
715597e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
715697e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
71573ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
71589371c9d4SSatish Balay         }
71599371c9d4SSatish Balay         break;
7160552f7358SJed Brown       case ADD_VALUES:
716197e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
716297e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
716397e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
716497e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
71653ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
71669371c9d4SSatish Balay         }
71679371c9d4SSatish Balay         break;
7168552f7358SJed Brown       case ADD_ALL_VALUES:
716997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
717097e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
717197e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
717297e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
71733ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
71749371c9d4SSatish Balay         }
71759371c9d4SSatish Balay         break;
7176304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
717797e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
717897e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
717997e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
718097e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
71813ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
71829371c9d4SSatish Balay         }
71839371c9d4SSatish Balay         break;
7184d71ae5a4SJacob Faibussowitsch       default:
7185d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7186552f7358SJed Brown       }
71879566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
71881a271a75SMatthew G. Knepley     }
7189552f7358SJed Brown   } else {
71901a271a75SMatthew G. Knepley     PetscInt            dof, off;
719197e99dd9SToby Isaac     const PetscInt    **perms = NULL;
719297e99dd9SToby Isaac     const PetscScalar **flips = NULL;
71931a271a75SMatthew G. Knepley 
71949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7195552f7358SJed Brown     switch (mode) {
7196552f7358SJed Brown     case INSERT_VALUES:
719797e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
719897e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
719997e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
720097e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
72019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
72023ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
72039371c9d4SSatish Balay       }
72049371c9d4SSatish Balay       break;
7205552f7358SJed Brown     case INSERT_ALL_VALUES:
720697e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
720797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
720897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
720997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
72109566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
72113ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
72129371c9d4SSatish Balay       }
72139371c9d4SSatish Balay       break;
7214a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
721597e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
721697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
721797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
721897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
72199566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
72203ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
72219371c9d4SSatish Balay       }
72229371c9d4SSatish Balay       break;
7223552f7358SJed Brown     case ADD_VALUES:
722497e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
722597e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
722697e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
722797e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
72289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
72293ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
72309371c9d4SSatish Balay       }
72319371c9d4SSatish Balay       break;
7232552f7358SJed Brown     case ADD_ALL_VALUES:
723397e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
723497e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
723597e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
723697e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
72379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
72383ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
72399371c9d4SSatish Balay       }
72409371c9d4SSatish Balay       break;
7241304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
724297e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
724397e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
724497e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
724597e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
72469566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
72473ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
72489371c9d4SSatish Balay       }
72499371c9d4SSatish Balay       break;
7250d71ae5a4SJacob Faibussowitsch     default:
7251d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7252552f7358SJed Brown     }
72539566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7254552f7358SJed Brown   }
72551a271a75SMatthew G. Knepley   /* Cleanup points */
72569566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
72571a271a75SMatthew G. Knepley   /* Cleanup array */
72589566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
72593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7260552f7358SJed Brown }
7261552f7358SJed Brown 
72625f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
7263d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7264d71ae5a4SJacob Faibussowitsch {
72655f790a90SMatthew G. Knepley   PetscFunctionBegin;
726611cc89d2SBarry Smith   *contains = PETSC_TRUE;
72675f790a90SMatthew G. Knepley   if (label) {
7268d6177c40SToby Isaac     PetscInt fdof;
72695f790a90SMatthew G. Knepley 
727011cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
727111cc89d2SBarry Smith     if (!*contains) {
72729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
72735f790a90SMatthew G. Knepley       *offset += fdof;
72743ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
72755f790a90SMatthew G. Knepley     }
72765f790a90SMatthew G. Knepley   }
72773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
72785f790a90SMatthew G. Knepley }
72795f790a90SMatthew G. Knepley 
728097529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7281d71ae5a4SJacob 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)
7282d71ae5a4SJacob Faibussowitsch {
7283e07394fbSMatthew G. Knepley   PetscSection    clSection;
7284e07394fbSMatthew G. Knepley   IS              clPoints;
7285e07394fbSMatthew G. Knepley   PetscScalar    *array;
7286e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
728797529cf3SJed Brown   const PetscInt *clp;
7288e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
728997e99dd9SToby Isaac   PetscInt        offset = 0, f;
7290e07394fbSMatthew G. Knepley 
7291e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
7292e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
72939566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7294e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7295e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
72969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7297e07394fbSMatthew G. Knepley   /* Get points */
729807218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7299e07394fbSMatthew G. Knepley   /* Get array */
73009566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7301e07394fbSMatthew G. Knepley   /* Get values */
7302e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
730397e99dd9SToby Isaac     const PetscInt    **perms = NULL;
730497e99dd9SToby Isaac     const PetscScalar **flips = NULL;
730511cc89d2SBarry Smith     PetscBool           contains;
730697e99dd9SToby Isaac 
7307e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
7308e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
7309e07394fbSMatthew G. Knepley         PetscInt fdof;
73109566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7311e07394fbSMatthew G. Knepley         offset += fdof;
7312e07394fbSMatthew G. Knepley       }
7313e07394fbSMatthew G. Knepley       continue;
7314e07394fbSMatthew G. Knepley     }
73159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7316e07394fbSMatthew G. Knepley     switch (mode) {
7317e07394fbSMatthew G. Knepley     case INSERT_VALUES:
731897e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
731997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
732097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
732197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
732211cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
732311cc89d2SBarry Smith         if (!contains) continue;
73249566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
73259371c9d4SSatish Balay       }
73269371c9d4SSatish Balay       break;
7327e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
732897e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
732997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
733097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
733197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
733211cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
733311cc89d2SBarry Smith         if (!contains) continue;
73349566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
73359371c9d4SSatish Balay       }
73369371c9d4SSatish Balay       break;
7337e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
733897e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
733997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
734097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
734197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
734211cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
734311cc89d2SBarry Smith         if (!contains) continue;
73449566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
73459371c9d4SSatish Balay       }
73469371c9d4SSatish Balay       break;
7347e07394fbSMatthew G. Knepley     case ADD_VALUES:
734897e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
734997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
735097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
735197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
735211cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
735311cc89d2SBarry Smith         if (!contains) continue;
73549566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
73559371c9d4SSatish Balay       }
73569371c9d4SSatish Balay       break;
7357e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
735897e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
735997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
736097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
736197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
736211cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
736311cc89d2SBarry Smith         if (!contains) continue;
73649566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
73659371c9d4SSatish Balay       }
73669371c9d4SSatish Balay       break;
7367d71ae5a4SJacob Faibussowitsch     default:
7368d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7369e07394fbSMatthew G. Knepley     }
73709566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7371e07394fbSMatthew G. Knepley   }
7372e07394fbSMatthew G. Knepley   /* Cleanup points */
73739566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7374e07394fbSMatthew G. Knepley   /* Cleanup array */
73759566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
73763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7377e07394fbSMatthew G. Knepley }
7378e07394fbSMatthew G. Knepley 
7379d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7380d71ae5a4SJacob Faibussowitsch {
7381552f7358SJed Brown   PetscMPIInt rank;
7382552f7358SJed Brown   PetscInt    i, j;
7383552f7358SJed Brown 
7384552f7358SJed Brown   PetscFunctionBegin;
73859566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
738663a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
738763a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
738863a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7389b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
73903ba16761SJacob Faibussowitsch   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7391b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
73929566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7393b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
7394519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
73959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7396552f7358SJed Brown #else
73979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7398552f7358SJed Brown #endif
7399552f7358SJed Brown     }
74009566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7401552f7358SJed Brown   }
74023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7403552f7358SJed Brown }
7404552f7358SJed Brown 
740505586334SMatthew G. Knepley /*
740605586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
740705586334SMatthew G. Knepley 
740805586334SMatthew G. Knepley   Input Parameters:
740905586334SMatthew G. Knepley + section - The section for this data layout
741036fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
741105586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
741205586334SMatthew G. Knepley . off     - The global offset of this point
741305586334SMatthew G. Knepley . loff    - The local offset of each field
7414a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
741505586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
741605586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
741705586334SMatthew G. Knepley 
741805586334SMatthew G. Knepley   Output Parameter:
741905586334SMatthew G. Knepley . indices - Indices for dofs on this point
742005586334SMatthew G. Knepley 
742105586334SMatthew G. Knepley   Level: developer
742205586334SMatthew G. Knepley 
742305586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
742405586334SMatthew G. Knepley */
7425d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7426d71ae5a4SJacob Faibussowitsch {
7427e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
7428552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
7429552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7430552f7358SJed Brown   PetscInt        cind = 0, k;
7431552f7358SJed Brown 
7432552f7358SJed Brown   PetscFunctionBegin;
743308401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
74349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
74359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7436552f7358SJed Brown   if (!cdof || setBC) {
743705586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
743805586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
743905586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
744005586334SMatthew G. Knepley 
744105586334SMatthew G. Knepley       indices[ind] = off + k;
7442552f7358SJed Brown     }
7443552f7358SJed Brown   } else {
74449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
74454acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
744605586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
744705586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
744805586334SMatthew G. Knepley 
74494acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
74504acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
745105586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
74524acb8e1eSToby Isaac         ++cind;
74534acb8e1eSToby Isaac       } else {
745436fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
7455552f7358SJed Brown       }
7456552f7358SJed Brown     }
7457552f7358SJed Brown   }
7458e6ccafaeSMatthew G Knepley   *loff += dof;
74593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7460552f7358SJed Brown }
7461552f7358SJed Brown 
74627e29afd2SMatthew G. Knepley /*
746336fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
74647e29afd2SMatthew G. Knepley 
746536fa2b79SJed Brown  Input Parameters:
746636fa2b79SJed Brown + section - a section (global or local)
746720f4b53cSBarry Smith - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
746836fa2b79SJed Brown . point - point within section
746936fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
747036fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
747136fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
747236fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
747336fa2b79SJed Brown . permsoff - offset
747436fa2b79SJed Brown - indperm - index permutation
747536fa2b79SJed Brown 
747636fa2b79SJed Brown  Output Parameter:
747736fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
747836fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
747936fa2b79SJed Brown 
748036fa2b79SJed Brown  Notes:
748136fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
748236fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
748336fa2b79SJed Brown  in the local vector.
748436fa2b79SJed Brown 
748536fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
748636fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
748736fa2b79SJed Brown 
748836fa2b79SJed Brown  Developer Note:
748936fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
749036fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
749136fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
749236fa2b79SJed Brown 
749336fa2b79SJed Brown  Example:
749436fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
749536fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
749636fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
749736fa2b79SJed 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.
749836fa2b79SJed Brown 
749936fa2b79SJed Brown  Level: developer
75007e29afd2SMatthew G. Knepley */
7501d71ae5a4SJacob 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[])
7502d71ae5a4SJacob Faibussowitsch {
7503552f7358SJed Brown   PetscInt numFields, foff, f;
7504552f7358SJed Brown 
7505552f7358SJed Brown   PetscFunctionBegin;
750608401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
75079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7508552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
75094acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
7510552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
75114acb8e1eSToby Isaac     PetscInt        cind = 0, b;
75124acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7513552f7358SJed Brown 
75149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
75159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7516552f7358SJed Brown     if (!cfdof || setBC) {
751705586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
751805586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
751905586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
752005586334SMatthew G. Knepley 
752105586334SMatthew G. Knepley         indices[ind] = off + foff + b;
752205586334SMatthew G. Knepley       }
7523552f7358SJed Brown     } else {
75249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
752505586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
752605586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
752705586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
752805586334SMatthew G. Knepley 
75294acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
753005586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
7531552f7358SJed Brown           ++cind;
7532552f7358SJed Brown         } else {
753336fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7534552f7358SJed Brown         }
7535552f7358SJed Brown       }
7536552f7358SJed Brown     }
753736fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7538552f7358SJed Brown     foffs[f] += fdof;
7539552f7358SJed Brown   }
75403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7541552f7358SJed Brown }
7542552f7358SJed Brown 
75437e29afd2SMatthew G. Knepley /*
75447e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
75457e29afd2SMatthew G. Knepley 
75467e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7547645102dcSJed Brown 
7548645102dcSJed Brown  Notes:
7549645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7550645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
75517e29afd2SMatthew G. Knepley */
7552d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7553d71ae5a4SJacob Faibussowitsch {
75547e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
75557e29afd2SMatthew G. Knepley 
75567e29afd2SMatthew G. Knepley   PetscFunctionBegin;
75579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
75587e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
75597e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
75607e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
75617e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
75627e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
75637e29afd2SMatthew G. Knepley 
75649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
75659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
75669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7567645102dcSJed Brown     if (!cfdof) {
756805586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
756905586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
757005586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
757105586334SMatthew G. Knepley 
757205586334SMatthew G. Knepley         indices[ind] = foff + b;
757305586334SMatthew G. Knepley       }
75747e29afd2SMatthew G. Knepley     } else {
75759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
757605586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
757705586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
757805586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
757905586334SMatthew G. Knepley 
75807e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
758105586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
75827e29afd2SMatthew G. Knepley           ++cind;
75837e29afd2SMatthew G. Knepley         } else {
758405586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
75857e29afd2SMatthew G. Knepley         }
75867e29afd2SMatthew G. Knepley       }
75877e29afd2SMatthew G. Knepley     }
75887e29afd2SMatthew G. Knepley     foffs[f] += fdof;
75897e29afd2SMatthew G. Knepley   }
75903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75917e29afd2SMatthew G. Knepley }
75927e29afd2SMatthew G. Knepley 
7593c789d87fSToby Isaac static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms)
7594c789d87fSToby Isaac {
7595c789d87fSToby Isaac   PetscInt numFields, sStart, sEnd, cStart, cEnd;
7596c789d87fSToby Isaac 
7597c789d87fSToby Isaac   PetscFunctionBegin;
7598c789d87fSToby Isaac   PetscCall(PetscSectionGetNumFields(section, &numFields));
7599c789d87fSToby Isaac   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7600c789d87fSToby Isaac   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7601c789d87fSToby Isaac   for (PetscInt p = 0; p < nPoints; p++) {
7602c789d87fSToby Isaac     PetscInt     b       = pnts[2 * p];
7603c789d87fSToby Isaac     PetscInt     bSecDof = 0, bOff;
7604c789d87fSToby Isaac     PetscInt     cSecDof = 0;
7605c789d87fSToby Isaac     PetscSection indices_section;
7606c789d87fSToby Isaac 
7607c789d87fSToby Isaac     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7608c789d87fSToby Isaac     if (!bSecDof) continue;
7609c789d87fSToby Isaac     if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof));
7610c789d87fSToby Isaac     indices_section = cSecDof > 0 ? cSec : section;
7611c789d87fSToby Isaac     if (numFields) {
7612c789d87fSToby Isaac       PetscInt fStart[32], fEnd[32];
7613c789d87fSToby Isaac 
7614c789d87fSToby Isaac       fStart[0] = 0;
7615c789d87fSToby Isaac       fEnd[0]   = 0;
7616c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7617c789d87fSToby Isaac         PetscInt fDof = 0;
7618c789d87fSToby Isaac 
7619c789d87fSToby Isaac         PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof));
7620c789d87fSToby Isaac         fStart[f + 1] = fStart[f] + fDof;
7621c789d87fSToby Isaac         fEnd[f + 1]   = fStart[f + 1];
7622c789d87fSToby Isaac       }
7623c789d87fSToby Isaac       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7624c789d87fSToby Isaac       // only apply permutations on one side
7625c789d87fSToby Isaac       PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices));
7626c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7627c789d87fSToby Isaac         for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); }
7628c789d87fSToby Isaac       }
7629c789d87fSToby Isaac     } else {
7630c789d87fSToby Isaac       PetscInt bEnd = 0;
7631c789d87fSToby Isaac 
7632c789d87fSToby Isaac       PetscCall(PetscSectionGetOffset(indices_section, b, &bOff));
7633c789d87fSToby Isaac       PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices));
7634c789d87fSToby Isaac 
7635c789d87fSToby Isaac       for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1);
7636c789d87fSToby Isaac     }
7637c789d87fSToby Isaac   }
7638c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
7639c789d87fSToby Isaac }
7640c789d87fSToby Isaac 
7641c789d87fSToby 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[])
7642d71ae5a4SJacob Faibussowitsch {
7643d3d1a6afSToby Isaac   Mat             cMat;
7644d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7645d3d1a6afSToby Isaac   IS              aIS;
7646d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7647a19ea1e9SMatthew G. Knepley   PetscInt        sStart = -1, sEnd = -1;
7648a19ea1e9SMatthew G. Knepley   PetscInt        cStart = -1, cEnd = -1;
7649d3d1a6afSToby Isaac   const PetscInt *anchors;
7650e969e7a5SJose E. Roman   PetscInt        numFields, p;
7651d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7652c789d87fSToby Isaac   PetscInt       *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices;
7653c789d87fSToby Isaac   PetscInt        oldOffsets[32];
7654d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7655c789d87fSToby Isaac   PetscInt        oldOffsetsCopy[32];
7656c789d87fSToby Isaac   PetscInt        newOffsetsCopy[32];
7657c789d87fSToby Isaac   PetscScalar    *modMat         = NULL;
7658d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7659d3d1a6afSToby Isaac 
7660d3d1a6afSToby Isaac   PetscFunctionBegin;
7661d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7662d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
76639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7664d3d1a6afSToby Isaac 
76659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7666d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7667d3d1a6afSToby Isaac   if (aSec) {
76689566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
7669c789d87fSToby Isaac     PetscCall(PetscArrayzero(oldOffsets, 32));
76709566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
76719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7672a19ea1e9SMatthew G. Knepley     PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
7673d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7674d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7675d3d1a6afSToby Isaac      * into the global matrix anyway) */
7676d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7677d3d1a6afSToby Isaac       PetscInt b    = points[p];
7678a19ea1e9SMatthew G. Knepley       PetscInt bDof = 0, bSecDof = 0;
7679d3d1a6afSToby Isaac 
7680a19ea1e9SMatthew G. Knepley       if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7681ad540459SPierre Jolivet       if (!bSecDof) continue;
7682c789d87fSToby Isaac 
7683c789d87fSToby Isaac       for (PetscInt f = 0; f < numFields; f++) {
7684c789d87fSToby Isaac         PetscInt fDof = 0;
7685c789d87fSToby Isaac 
7686c789d87fSToby Isaac         PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7687c789d87fSToby Isaac         oldOffsets[f + 1] += fDof;
7688c789d87fSToby Isaac       }
768948a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7690d3d1a6afSToby Isaac       if (bDof) {
7691d3d1a6afSToby Isaac         /* this point is constrained */
7692d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7693d3d1a6afSToby Isaac         PetscInt bOff, q;
7694d3d1a6afSToby Isaac 
76959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7696d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7697d3d1a6afSToby Isaac           PetscInt a    = anchors[bOff + q];
7698a19ea1e9SMatthew G. Knepley           PetscInt aDof = 0;
7699d3d1a6afSToby Isaac 
7700a19ea1e9SMatthew G. Knepley           if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7701c789d87fSToby Isaac           if (aDof) {
7702c789d87fSToby Isaac             anyConstrained = PETSC_TRUE;
7703c789d87fSToby Isaac             newNumPoints += 1;
7704c789d87fSToby Isaac           }
7705d3d1a6afSToby Isaac           newNumIndices += aDof;
7706e969e7a5SJose E. Roman           for (PetscInt f = 0; f < numFields; ++f) {
7707a19ea1e9SMatthew G. Knepley             PetscInt fDof = 0;
7708d3d1a6afSToby Isaac 
7709a19ea1e9SMatthew G. Knepley             if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7710d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7711d3d1a6afSToby Isaac           }
7712d3d1a6afSToby Isaac         }
77139371c9d4SSatish Balay       } else {
7714d3d1a6afSToby Isaac         /* this point is not constrained */
7715d3d1a6afSToby Isaac         newNumPoints++;
77164b2f2278SToby Isaac         newNumIndices += bSecDof;
7717e969e7a5SJose E. Roman         for (PetscInt f = 0; f < numFields; ++f) {
7718d3d1a6afSToby Isaac           PetscInt fDof;
7719d3d1a6afSToby Isaac 
77209566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7721d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7722d3d1a6afSToby Isaac         }
7723d3d1a6afSToby Isaac       }
7724d3d1a6afSToby Isaac     }
7725d3d1a6afSToby Isaac   }
7726d3d1a6afSToby Isaac   if (!anyConstrained) {
772772b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
772872b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
772972b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
7730c789d87fSToby Isaac     if (outMat) *outMat = NULL;
77319566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
77323ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7733d3d1a6afSToby Isaac   }
7734d3d1a6afSToby Isaac 
77356ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
77366ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
77376ecaa68aSToby Isaac 
7738e969e7a5SJose E. Roman   for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7739e969e7a5SJose E. Roman   for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f];
7740d3d1a6afSToby Isaac 
7741c789d87fSToby Isaac   if (!outPoints && !outMat) {
77426ecaa68aSToby Isaac     if (offsets) {
7743e969e7a5SJose E. Roman       for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
77446ecaa68aSToby Isaac     }
77459566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
77463ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
77476ecaa68aSToby Isaac   }
77486ecaa68aSToby Isaac 
77491dca8a05SBarry 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);
7750c789d87fSToby 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);
7751d3d1a6afSToby Isaac 
77529566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7753a19ea1e9SMatthew G. Knepley   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
7754d3d1a6afSToby Isaac 
77556ecaa68aSToby Isaac   /* output arrays */
77569566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7757c789d87fSToby Isaac   PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints));
77586ecaa68aSToby Isaac 
7759c789d87fSToby Isaac   // get the new Points
7760c789d87fSToby Isaac   for (PetscInt p = 0, newP = 0; p < numPoints; p++) {
7761d3d1a6afSToby Isaac     PetscInt b    = points[2 * p];
7762c789d87fSToby Isaac     PetscInt bDof = 0, bSecDof = 0, bOff;
7763d3d1a6afSToby Isaac 
7764a19ea1e9SMatthew G. Knepley     if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7765ad540459SPierre Jolivet     if (!bSecDof) continue;
776648a46eb9SPierre Jolivet     if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7767d3d1a6afSToby Isaac     if (bDof) {
77689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7769c789d87fSToby Isaac       for (PetscInt q = 0; q < bDof; q++) {
7770a19ea1e9SMatthew G. Knepley         PetscInt a = anchors[bOff + q], aDof = 0;
7771d3d1a6afSToby Isaac 
7772a19ea1e9SMatthew G. Knepley         if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof));
7773c789d87fSToby Isaac         if (aDof) {
7774c789d87fSToby Isaac           newPoints[2 * newP]     = a;
7775c789d87fSToby Isaac           newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation
7776d3d1a6afSToby Isaac           newP++;
7777d3d1a6afSToby Isaac         }
7778d3d1a6afSToby Isaac       }
7779d3d1a6afSToby Isaac     } else {
7780d3d1a6afSToby Isaac       newPoints[2 * newP]     = b;
7781c789d87fSToby Isaac       newPoints[2 * newP + 1] = points[2 * p + 1];
7782d3d1a6afSToby Isaac       newP++;
7783d3d1a6afSToby Isaac     }
7784d3d1a6afSToby Isaac   }
7785d3d1a6afSToby Isaac 
7786c789d87fSToby Isaac   if (outMat) {
7787c789d87fSToby Isaac     PetscScalar *tmpMat;
7788c789d87fSToby Isaac     PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32));
7789c789d87fSToby Isaac     PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32));
7790c789d87fSToby Isaac 
7791c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices));
7792c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7793c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7794c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7795c789d87fSToby Isaac 
7796c789d87fSToby Isaac     for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1;
7797c789d87fSToby Isaac     for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1;
7798c789d87fSToby Isaac 
7799c789d87fSToby Isaac     PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms));
7800c789d87fSToby Isaac     PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL));
7801c789d87fSToby Isaac 
7802c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
7803c789d87fSToby Isaac     PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
7804c789d87fSToby Isaac     PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices));
7805c789d87fSToby Isaac     // for each field, insert the anchor modification into modMat
7806c789d87fSToby Isaac     for (PetscInt f = 0; f < PetscMax(1, numFields); f++) {
7807c789d87fSToby Isaac       PetscInt fStart    = oldOffsets[f];
7808c789d87fSToby Isaac       PetscInt fNewStart = newOffsets[f];
7809c789d87fSToby Isaac       for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) {
7810c789d87fSToby Isaac         PetscInt b    = points[2 * p];
7811c789d87fSToby Isaac         PetscInt bDof = 0, bSecDof = 0, bOff;
7812c789d87fSToby Isaac 
7813c789d87fSToby Isaac         if (b >= sStart && b < sEnd) {
7814d3d1a6afSToby Isaac           if (numFields) {
7815c789d87fSToby Isaac             PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof));
78169371c9d4SSatish Balay           } else {
7817c789d87fSToby Isaac             PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7818d3d1a6afSToby Isaac           }
7819d3d1a6afSToby Isaac         }
7820c789d87fSToby Isaac         if (!bSecDof) continue;
7821c789d87fSToby Isaac         if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7822c789d87fSToby Isaac         if (bDof) {
7823c789d87fSToby Isaac           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7824c789d87fSToby Isaac           for (PetscInt q = 0; q < bDof; q++, newP++) {
7825c789d87fSToby Isaac             PetscInt a = anchors[bOff + q], aDof = 0;
7826d3d1a6afSToby Isaac 
7827c789d87fSToby Isaac             if (a >= sStart && a < sEnd) {
7828d3d1a6afSToby Isaac               if (numFields) {
7829c789d87fSToby Isaac                 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
7830c789d87fSToby Isaac               } else {
7831c789d87fSToby Isaac                 PetscCall(PetscSectionGetDof(section, a, &aDof));
7832d3d1a6afSToby Isaac               }
7833d3d1a6afSToby Isaac             }
7834c789d87fSToby Isaac             if (aDof) {
7835c789d87fSToby Isaac               PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat));
7836c789d87fSToby Isaac               for (PetscInt d = 0; d < bSecDof; d++) {
7837c789d87fSToby Isaac                 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e];
7838c789d87fSToby Isaac               }
7839c789d87fSToby Isaac             }
7840c789d87fSToby Isaac             oNew += aDof;
7841c789d87fSToby Isaac           }
78429371c9d4SSatish Balay         } else {
7843c789d87fSToby Isaac           // Insert the identity matrix in this block
7844c789d87fSToby Isaac           for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1;
7845c789d87fSToby Isaac           oNew += bSecDof;
7846c789d87fSToby Isaac           newP++;
7847d3d1a6afSToby Isaac         }
7848c789d87fSToby Isaac         o += bSecDof;
7849d3d1a6afSToby Isaac       }
7850d3d1a6afSToby Isaac     }
7851d3d1a6afSToby Isaac 
7852c789d87fSToby Isaac     *outMat = modMat;
78536ecaa68aSToby Isaac 
7854c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat));
7855c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices));
7856c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices));
7857c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices));
7858c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices));
7859d3d1a6afSToby Isaac   }
78609566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
7861d3d1a6afSToby Isaac 
7862d3d1a6afSToby Isaac   /* output */
78636ecaa68aSToby Isaac   if (outPoints) {
7864d3d1a6afSToby Isaac     *outPoints = newPoints;
78659371c9d4SSatish Balay   } else {
78669566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
78676ecaa68aSToby Isaac   }
7868e969e7a5SJose E. Roman   for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
78693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7870d3d1a6afSToby Isaac }
7871d3d1a6afSToby Isaac 
7872c789d87fSToby 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)
7873c789d87fSToby Isaac {
7874c789d87fSToby Isaac   PetscScalar *modMat        = NULL;
7875c789d87fSToby Isaac   PetscInt     newNumIndices = -1;
78767cd05799SMatthew G. Knepley 
7877c789d87fSToby Isaac   PetscFunctionBegin;
7878c789d87fSToby 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.
7879c789d87fSToby Isaac      modMat is that matrix C */
7880c789d87fSToby Isaac   PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL));
7881c789d87fSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
7882c789d87fSToby Isaac   if (modMat) {
7883c789d87fSToby Isaac     const PetscScalar *newValues = values;
78847cd05799SMatthew G. Knepley 
7885c789d87fSToby Isaac     if (multiplyRight) {
7886c789d87fSToby Isaac       PetscScalar *newNewValues = NULL;
7887*6497c311SBarry Smith       PetscBLASInt M, N, K;
7888c789d87fSToby Isaac       PetscScalar  a = 1.0, b = 0.0;
78897cd05799SMatthew G. Knepley 
7890c789d87fSToby 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);
78917cd05799SMatthew G. Knepley 
7892*6497c311SBarry Smith       PetscCall(PetscBLASIntCast(newNumIndices, &M));
7893*6497c311SBarry Smith       PetscCall(PetscBLASIntCast(numRows, &N));
7894*6497c311SBarry Smith       PetscCall(PetscBLASIntCast(numIndices, &K));
7895c789d87fSToby Isaac       PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues));
7896c789d87fSToby Isaac       // row-major to column-major conversion, right multiplication becomes left multiplication
7897c789d87fSToby Isaac       PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M));
7898c789d87fSToby Isaac       numCols   = newNumIndices;
7899c789d87fSToby Isaac       newValues = newNewValues;
7900c789d87fSToby Isaac     }
7901a1cb98faSBarry Smith 
7902c789d87fSToby Isaac     if (multiplyLeft) {
7903c789d87fSToby Isaac       PetscScalar *newNewValues = NULL;
7904*6497c311SBarry Smith       PetscBLASInt M, N, K;
7905c789d87fSToby Isaac       PetscScalar  a = 1.0, b = 0.0;
79067cd05799SMatthew G. Knepley 
7907c789d87fSToby 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);
7908c789d87fSToby Isaac 
7909*6497c311SBarry Smith       PetscCall(PetscBLASIntCast(numCols, &M));
7910*6497c311SBarry Smith       PetscCall(PetscBLASIntCast(newNumIndices, &N));
7911*6497c311SBarry Smith       PetscCall(PetscBLASIntCast(numIndices, &K));
7912c789d87fSToby Isaac       PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues));
7913c789d87fSToby Isaac       // row-major to column-major conversion, left multiplication becomes right multiplication
7914c789d87fSToby Isaac       PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M));
7915c789d87fSToby Isaac       if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues));
7916c789d87fSToby Isaac       newValues = newNewValues;
7917c789d87fSToby Isaac     }
7918c789d87fSToby Isaac     *outValues = (PetscScalar *)newValues;
7919c789d87fSToby Isaac     PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat));
7920c789d87fSToby Isaac   }
7921c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
7922c789d87fSToby Isaac }
7923c789d87fSToby Isaac 
7924c789d87fSToby 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)
7925c789d87fSToby Isaac {
7926c789d87fSToby Isaac   PetscFunctionBegin;
7927c789d87fSToby Isaac   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft));
7928c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
7929c789d87fSToby Isaac }
7930c789d87fSToby Isaac 
7931c789d87fSToby Isaac static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize)
7932c789d87fSToby Isaac {
7933c789d87fSToby Isaac   /* Closure ordering */
7934c789d87fSToby Isaac   PetscSection    clSection;
7935c789d87fSToby Isaac   IS              clPoints;
7936c789d87fSToby Isaac   const PetscInt *clp;
7937c789d87fSToby Isaac   PetscInt       *points;
7938c789d87fSToby Isaac   PetscInt        Ncl, Ni = 0;
7939c789d87fSToby Isaac 
7940c789d87fSToby Isaac   PetscFunctionBeginHot;
7941c789d87fSToby Isaac   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7942c789d87fSToby Isaac   for (PetscInt p = 0; p < Ncl * 2; p += 2) {
7943c789d87fSToby Isaac     PetscInt dof;
7944c789d87fSToby Isaac 
7945c789d87fSToby Isaac     PetscCall(PetscSectionGetDof(section, points[p], &dof));
7946c789d87fSToby Isaac     Ni += dof;
7947c789d87fSToby Isaac   }
7948c789d87fSToby Isaac   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7949c789d87fSToby Isaac   *closureSize = Ni;
7950c789d87fSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
7951c789d87fSToby Isaac }
7952c789d87fSToby Isaac 
7953c789d87fSToby 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)
7954d71ae5a4SJacob Faibussowitsch {
795571f0bbf9SMatthew G. Knepley   /* Closure ordering */
79567773e69fSMatthew G. Knepley   PetscSection    clSection;
79577773e69fSMatthew G. Knepley   IS              clPoints;
795871f0bbf9SMatthew G. Knepley   const PetscInt *clp;
795971f0bbf9SMatthew G. Knepley   PetscInt       *points;
796071f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
796171f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
79624acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
796371f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
796471f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
796571f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
796671f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
796771f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
796871f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
796971f0bbf9SMatthew G. Knepley 
797071f0bbf9SMatthew G. Knepley   PetscInt *idx;
797171f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
797271f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
79737caea556SToby Isaac   PetscInt  idxStart, idxEnd;
7974c789d87fSToby Isaac   PetscInt  nRows, nCols;
79757773e69fSMatthew G. Knepley 
797671f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
79777773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
79787773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
797936fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7980c789d87fSToby Isaac   PetscAssertPointer(numRows, 6);
7981c789d87fSToby Isaac   PetscAssertPointer(numCols, 7);
7982c789d87fSToby Isaac   if (indices) PetscAssertPointer(indices, 8);
7983c789d87fSToby Isaac   if (outOffsets) PetscAssertPointer(outOffsets, 9);
7984c789d87fSToby Isaac   if (values) PetscAssertPointer(values, 10);
79859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
798663a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
79879566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
798871f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
798907218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7990c459fbc1SJed Brown   if (useClPerm) {
7991c459fbc1SJed Brown     PetscInt depth, clsize;
79929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7993c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
7994c459fbc1SJed Brown       PetscInt dof;
79959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7996c459fbc1SJed Brown       clsize += dof;
7997c459fbc1SJed Brown     }
79989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7999c459fbc1SJed Brown   }
800071f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
800171f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
80027773e69fSMatthew G. Knepley     PetscInt dof, fdof;
80037773e69fSMatthew G. Knepley 
80049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
80057773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
80069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
80077773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
80087773e69fSMatthew G. Knepley     }
800971f0bbf9SMatthew G. Knepley     Ni += dof;
80107773e69fSMatthew G. Knepley   }
8011c789d87fSToby Isaac   if (*numRows == -1) *numRows = Ni;
8012c789d87fSToby Isaac   if (*numCols == -1) *numCols = Ni;
8013c789d87fSToby Isaac   nRows = *numRows;
8014c789d87fSToby Isaac   nCols = *numCols;
80157773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
80161dca8a05SBarry 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);
801771f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
8018c789d87fSToby Isaac   if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols);
8019c789d87fSToby Isaac   if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows);
802071f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
80219566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
80229566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
802371f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
802471f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
802571f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
80266ecaa68aSToby Isaac 
802771f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
802871f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
802971f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
803071f0bbf9SMatthew G. Knepley 
80319566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
80329566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
803371f0bbf9SMatthew G. Knepley         if (flip) {
803471f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
803571f0bbf9SMatthew G. Knepley 
803671f0bbf9SMatthew G. Knepley           if (!valCopy) {
80379566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
803871f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
803971f0bbf9SMatthew G. Knepley             *values = valCopy;
804071f0bbf9SMatthew G. Knepley           }
804171f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
804271f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
804371f0bbf9SMatthew G. Knepley 
8044c789d87fSToby Isaac             if (multiplyRight) {
8045c789d87fSToby Isaac               for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; }
8046c789d87fSToby Isaac             }
8047c789d87fSToby Isaac             if (multiplyLeft) {
8048c789d87fSToby Isaac               for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; }
80496ecaa68aSToby Isaac             }
80506ecaa68aSToby Isaac           }
805171f0bbf9SMatthew G. Knepley         }
805271f0bbf9SMatthew G. Knepley         foffset += fdof;
805371f0bbf9SMatthew G. Knepley       }
805471f0bbf9SMatthew G. Knepley     }
805571f0bbf9SMatthew G. Knepley   }
805671f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
8057c789d87fSToby Isaac   PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft));
805871f0bbf9SMatthew G. Knepley   if (NclC) {
8059c789d87fSToby Isaac     if (multiplyRight) { *numCols = nCols = NiC; }
8060c789d87fSToby Isaac     if (multiplyLeft) { *numRows = nRows = NiC; }
80619566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
806271f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
80639566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
80649566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
806571f0bbf9SMatthew G. Knepley     }
806671f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
80679566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
80689566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
806971f0bbf9SMatthew G. Knepley     }
80709566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
807171f0bbf9SMatthew G. Knepley     Ncl    = NclC;
807271f0bbf9SMatthew G. Knepley     Ni     = NiC;
807371f0bbf9SMatthew G. Knepley     points = pointsC;
807471f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
807571f0bbf9SMatthew G. Knepley   }
807671f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
80779566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
80787caea556SToby Isaac   PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd));
807971f0bbf9SMatthew G. Knepley   if (Nf) {
808071f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
808171f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
808271f0bbf9SMatthew G. Knepley 
80839371c9d4SSatish Balay     if (outOffsets) {
80849371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
80859371c9d4SSatish Balay     }
80869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
808771f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
808871f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
808971f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
809071f0bbf9SMatthew G. Knepley 
80919566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
80927773e69fSMatthew G. Knepley       }
80937773e69fSMatthew G. Knepley     } else {
809471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
809571f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
809671f0bbf9SMatthew G. Knepley 
80977caea556SToby Isaac         if (pnt < idxStart || pnt >= idxEnd) continue;
80989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
809971f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
810071f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
810171f0bbf9SMatthew G. Knepley          * global section. */
81029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
810371f0bbf9SMatthew G. Knepley       }
810471f0bbf9SMatthew G. Knepley     }
810571f0bbf9SMatthew G. Knepley   } else {
810671f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
810771f0bbf9SMatthew G. Knepley 
810871f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
810971f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
81104acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
81114acb8e1eSToby Isaac 
81127caea556SToby Isaac       if (pnt < idxStart || pnt >= idxEnd) continue;
81139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
811471f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
811571f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
81169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
81177773e69fSMatthew G. Knepley     }
81187773e69fSMatthew G. Knepley   }
811971f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
812071f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
81219566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
81229566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
81234acb8e1eSToby Isaac   }
812471f0bbf9SMatthew G. Knepley   if (NclC) {
81259566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
81267773e69fSMatthew G. Knepley   } else {
81279566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
81287773e69fSMatthew G. Knepley   }
812971f0bbf9SMatthew G. Knepley 
813071f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
81313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81327773e69fSMatthew G. Knepley }
81337773e69fSMatthew G. Knepley 
8134d3d1a6afSToby Isaac /*@C
8135d3d1a6afSToby Isaac   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
8136d3d1a6afSToby Isaac 
8137d3d1a6afSToby Isaac   Not collective
8138d3d1a6afSToby Isaac 
8139d3d1a6afSToby Isaac   Input Parameters:
8140d3d1a6afSToby Isaac + dm         - The `DM`
8141d3d1a6afSToby Isaac . section    - The `PetscSection` describing the points (a local section)
8142d3d1a6afSToby Isaac . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
8143d3d1a6afSToby Isaac . point      - The point defining the closure
8144d3d1a6afSToby Isaac - useClPerm  - Use the closure point permutation if available
8145d3d1a6afSToby Isaac 
8146d3d1a6afSToby Isaac   Output Parameters:
8147d3d1a6afSToby Isaac + numIndices - The number of dof indices in the closure of point with the input sections
8148d3d1a6afSToby Isaac . indices    - The dof indices
8149d3d1a6afSToby Isaac . outOffsets - Array to write the field offsets into, or `NULL`
8150d3d1a6afSToby Isaac - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
8151d3d1a6afSToby Isaac 
8152d3d1a6afSToby Isaac   Level: advanced
8153d3d1a6afSToby Isaac 
8154d3d1a6afSToby Isaac   Notes:
81552c9a7b26SBarry Smith   Call `DMPlexRestoreClosureIndices()` to free allocated memory
8156d3d1a6afSToby Isaac 
8157d3d1a6afSToby Isaac   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
8158d3d1a6afSToby Isaac   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
8159d3d1a6afSToby Isaac   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
8160d3d1a6afSToby Isaac   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
8161d3d1a6afSToby Isaac   indices (with the above semantics) are implied.
8162d3d1a6afSToby Isaac 
8163d3d1a6afSToby Isaac .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
8164d3d1a6afSToby Isaac           `PetscSection`, `DMGetGlobalSection()`
8165d3d1a6afSToby Isaac @*/
8166d3d1a6afSToby Isaac PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
8167d3d1a6afSToby Isaac {
8168c789d87fSToby Isaac   PetscInt numRows = -1, numCols = -1;
8169d3d1a6afSToby Isaac 
8170d3d1a6afSToby Isaac   PetscFunctionBeginHot;
8171c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE));
8172c789d87fSToby Isaac   PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols);
8173c789d87fSToby Isaac   *numIndices = numRows;
81747773e69fSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
81757773e69fSMatthew G. Knepley }
81767773e69fSMatthew G. Knepley 
81777cd05799SMatthew G. Knepley /*@C
817871f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
81797cd05799SMatthew G. Knepley 
81807cd05799SMatthew G. Knepley   Not collective
81817cd05799SMatthew G. Knepley 
81827cd05799SMatthew G. Knepley   Input Parameters:
8183a1cb98faSBarry Smith + dm         - The `DM`
8184a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
8185a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
818671f0bbf9SMatthew G. Knepley . point      - The point defining the closure
818771f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
818871f0bbf9SMatthew G. Knepley 
818971f0bbf9SMatthew G. Knepley   Output Parameters:
819071f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
819171f0bbf9SMatthew G. Knepley . indices    - The dof indices
819220f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
819320f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
819471f0bbf9SMatthew G. Knepley 
8195a1cb98faSBarry Smith   Level: advanced
819671f0bbf9SMatthew G. Knepley 
8197a1cb98faSBarry Smith   Notes:
8198a1cb98faSBarry Smith   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
8199a1cb98faSBarry Smith 
8200a1cb98faSBarry Smith   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
820171f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
820271f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
820371f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
820471f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
82057cd05799SMatthew G. Knepley 
82061cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
82077cd05799SMatthew G. Knepley @*/
8208d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
8209d71ae5a4SJacob Faibussowitsch {
82107773e69fSMatthew G. Knepley   PetscFunctionBegin;
82117773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
82124f572ea9SToby Isaac   PetscAssertPointer(indices, 7);
82139566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
82143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
82157773e69fSMatthew G. Knepley }
82167773e69fSMatthew G. Knepley 
8217e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8218d71ae5a4SJacob Faibussowitsch {
8219552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
8220552f7358SJed Brown   PetscInt          *indices;
822171f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
822271f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
8223552f7358SJed Brown   PetscErrorCode     ierr;
8224552f7358SJed Brown 
8225552f7358SJed Brown   PetscFunctionBegin;
8226552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
82279566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
82283dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
82299566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
82303dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
8231e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 5);
8232552f7358SJed Brown 
8233e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
82340d644c17SKarl Rupp 
82359566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
8236d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
82374a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8238552f7358SJed Brown   if (ierr) {
8239552f7358SJed Brown     PetscMPIInt rank;
8240552f7358SJed Brown 
82419566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
82429566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
82439566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
82449566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
82459566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8246c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
8247552f7358SJed Brown   }
82484a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
82494a1e0b3eSMatthew G. Knepley     PetscInt i;
82509566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
825163a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
82529566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
82534a1e0b3eSMatthew G. Knepley   }
825471f0bbf9SMatthew G. Knepley 
82559566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
82569566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
82573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
82584acb8e1eSToby Isaac }
825971f0bbf9SMatthew G. Knepley 
82604a1e0b3eSMatthew G. Knepley /*@C
8261e8e188d2SZach Atkins   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
8262e8e188d2SZach Atkins 
8263e8e188d2SZach Atkins   Not collective
8264e8e188d2SZach Atkins 
8265e8e188d2SZach Atkins   Input Parameters:
8266e8e188d2SZach Atkins + dm            - The `DM`
8267e8e188d2SZach Atkins . section       - The section describing the layout in `v`, or `NULL` to use the default section
8268e8e188d2SZach Atkins . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
8269e8e188d2SZach Atkins . A             - The matrix
8270e8e188d2SZach Atkins . point         - The point in the `DM`
8271e8e188d2SZach Atkins . values        - The array of values
8272e8e188d2SZach Atkins - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8273e8e188d2SZach Atkins 
8274e8e188d2SZach Atkins   Level: intermediate
8275e8e188d2SZach Atkins 
8276e8e188d2SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8277e8e188d2SZach Atkins @*/
8278e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8279e8e188d2SZach Atkins {
8280e8e188d2SZach Atkins   PetscFunctionBegin;
8281e8e188d2SZach Atkins   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
8282e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
8283e8e188d2SZach Atkins }
8284e8e188d2SZach Atkins 
8285e8e188d2SZach Atkins /*@C
828660225df5SJacob Faibussowitsch   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
82874a1e0b3eSMatthew G. Knepley 
82884a1e0b3eSMatthew G. Knepley   Not collective
82894a1e0b3eSMatthew G. Knepley 
82904a1e0b3eSMatthew G. Knepley   Input Parameters:
8291a1cb98faSBarry Smith + dmRow            - The `DM` for the row fields
829220f4b53cSBarry Smith . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
8293e8e188d2SZach Atkins . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
829420f4b53cSBarry Smith . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
8295a1cb98faSBarry Smith . dmCol            - The `DM` for the column fields
829620f4b53cSBarry Smith . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
8297e8e188d2SZach Atkins . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
829820f4b53cSBarry Smith . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
82994a1e0b3eSMatthew G. Knepley . A                - The matrix
8300a1cb98faSBarry Smith . point            - The point in the `DM`
83014a1e0b3eSMatthew G. Knepley . values           - The array of values
8302a1cb98faSBarry Smith - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
83034a1e0b3eSMatthew G. Knepley 
83044a1e0b3eSMatthew G. Knepley   Level: intermediate
83054a1e0b3eSMatthew G. Knepley 
83061cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
83074a1e0b3eSMatthew G. Knepley @*/
8308e8e188d2SZach 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)
8309d71ae5a4SJacob Faibussowitsch {
831071f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
831171f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
8312c789d87fSToby Isaac   PetscInt           numIndicesRow = -1, numIndicesCol = -1;
83137caea556SToby Isaac   const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2;
8314c789d87fSToby Isaac 
831571f0bbf9SMatthew G. Knepley   PetscErrorCode ierr;
831671f0bbf9SMatthew G. Knepley 
831771f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
831871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
83199566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
832071f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
83219566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
832271f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
8323e8e188d2SZach Atkins   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5);
83249566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
8325e8e188d2SZach Atkins   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6);
83269566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
8327e8e188d2SZach Atkins   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7);
8328e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 9);
832971f0bbf9SMatthew G. Knepley 
8330c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow));
8331c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol));
83327caea556SToby Isaac   valuesV1 = valuesV0;
8333c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE));
83347caea556SToby Isaac   valuesV2 = valuesV1;
8335c789d87fSToby Isaac   PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE));
833671f0bbf9SMatthew G. Knepley 
8337c789d87fSToby Isaac   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2));
8338d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8339c789d87fSToby Isaac   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode);
834071f0bbf9SMatthew G. Knepley   if (ierr) {
834171f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
834271f0bbf9SMatthew G. Knepley 
83439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
83449566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
83459566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
83467caea556SToby Isaac     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2));
83477caea556SToby Isaac     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
83487caea556SToby Isaac     if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
83497caea556SToby Isaac     if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
8350d3d1a6afSToby Isaac   }
835171f0bbf9SMatthew G. Knepley 
83527caea556SToby Isaac   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2));
83537caea556SToby Isaac   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1));
83547caea556SToby Isaac   if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2));
83557caea556SToby Isaac   if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1));
83563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8357552f7358SJed Brown }
8358552f7358SJed Brown 
8359d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8360d71ae5a4SJacob Faibussowitsch {
8361de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
8362de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8363de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
8364de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
836517c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8366de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
8367412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
83684ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8369de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
8370de41b84cSMatthew G. Knepley 
8371de41b84cSMatthew G. Knepley   PetscFunctionBegin;
8372de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8373de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
83749566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8375de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
83769566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8377de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
83789566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8379de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
83809566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8381de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8382de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
83839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
838463a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
83859566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
83869566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
8387de41b84cSMatthew G. Knepley   /* Column indices */
83889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
83894ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
8390de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
8391de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
83929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8393de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8394de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8395de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
8396de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
8397de41b84cSMatthew G. Knepley       ++q;
8398de41b84cSMatthew G. Knepley     }
8399de41b84cSMatthew G. Knepley   }
8400de41b84cSMatthew G. Knepley   numCPoints = q;
8401de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8402de41b84cSMatthew G. Knepley     PetscInt fdof;
8403de41b84cSMatthew G. Knepley 
84049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
84054ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8406de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
84079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8408de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
8409de41b84cSMatthew G. Knepley     }
8410de41b84cSMatthew G. Knepley     numCIndices += dof;
8411de41b84cSMatthew G. Knepley   }
8412de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8413de41b84cSMatthew G. Knepley   /* Row indices */
84149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8415412e9a14SMatthew G. Knepley   {
8416012bc364SMatthew G. Knepley     DMPlexTransform tr;
8417012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8418012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8419012bc364SMatthew G. Knepley 
84209566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
84219566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
84229566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8423012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
84249566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8425412e9a14SMatthew G. Knepley   }
84269566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8427de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
8428de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
84299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8430de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
84319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8432de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
8433de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
84349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
84354ca5e9f5SMatthew G. Knepley         if (!dof) continue;
84369371c9d4SSatish Balay         for (s = 0; s < q; ++s)
84379371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
84384ca5e9f5SMatthew G. Knepley         if (s < q) continue;
8439de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
8440de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8441de41b84cSMatthew G. Knepley         ++q;
8442de41b84cSMatthew G. Knepley       }
8443de41b84cSMatthew G. Knepley     }
84449566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8445de41b84cSMatthew G. Knepley   }
8446de41b84cSMatthew G. Knepley   numFPoints = q;
8447de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8448de41b84cSMatthew G. Knepley     PetscInt fdof;
8449de41b84cSMatthew G. Knepley 
84509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
84514ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8452de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
84539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8454de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
8455de41b84cSMatthew G. Knepley     }
8456de41b84cSMatthew G. Knepley     numFIndices += dof;
8457de41b84cSMatthew G. Knepley   }
8458de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8459de41b84cSMatthew G. Knepley 
84601dca8a05SBarry 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);
84611dca8a05SBarry 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);
84629566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
84639566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8464de41b84cSMatthew G. Knepley   if (numFields) {
84654acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
84664acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
84674acb8e1eSToby Isaac 
84684acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
84699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
84709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8471de41b84cSMatthew G. Knepley     }
84724acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
84739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
84749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
84754acb8e1eSToby Isaac     }
84764acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
84779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
84789566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
84794acb8e1eSToby Isaac     }
84804acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
84819566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
84829566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8483de41b84cSMatthew G. Knepley     }
8484de41b84cSMatthew G. Knepley   } else {
84854acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
84864acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
84874acb8e1eSToby Isaac 
84889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
84899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
84904acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
84914acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
84924acb8e1eSToby Isaac 
84939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
84949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8495de41b84cSMatthew G. Knepley     }
84964acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
84974acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
84984acb8e1eSToby Isaac 
84999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
85009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8501de41b84cSMatthew G. Knepley     }
85029566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
85039566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8504de41b84cSMatthew G. Knepley   }
85059566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
85064acb8e1eSToby Isaac   /* TODO: flips */
8507d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8508de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8509de41b84cSMatthew G. Knepley   if (ierr) {
8510de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8511de41b84cSMatthew G. Knepley 
85129566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
85139566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
85149566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
85159566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
85169566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8517de41b84cSMatthew G. Knepley   }
85189566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
85199566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
85209566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
85219566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
85223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8523de41b84cSMatthew G. Knepley }
8524de41b84cSMatthew G. Knepley 
8525d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8526d71ae5a4SJacob Faibussowitsch {
85277c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
85287c927364SMatthew G. Knepley   PetscInt       *cpoints      = NULL;
8529230af79eSStefano Zampini   PetscInt        foffsets[32] = {0}, coffsets[32] = {0};
853017c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8531412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
85327c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
85337c927364SMatthew G. Knepley 
85347c927364SMatthew G. Knepley   PetscFunctionBegin;
85357c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
85367c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
85379566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
85387c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
85399566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
85407c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
85419566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
85427c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
85439566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
85447c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
85459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
854663a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
85477c927364SMatthew G. Knepley   /* Column indices */
85489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
85497c927364SMatthew G. Knepley   maxFPoints = numCPoints;
85507c927364SMatthew G. Knepley   /* Compress out points not in the section */
85517c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
85529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
85537c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
85547c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
85557c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
85567c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
85577c927364SMatthew G. Knepley       ++q;
85587c927364SMatthew G. Knepley     }
85597c927364SMatthew G. Knepley   }
85607c927364SMatthew G. Knepley   numCPoints = q;
85617c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
85627c927364SMatthew G. Knepley     PetscInt fdof;
85637c927364SMatthew G. Knepley 
85649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
85657c927364SMatthew G. Knepley     if (!dof) continue;
85667c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
85679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
85687c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
85697c927364SMatthew G. Knepley     }
85707c927364SMatthew G. Knepley     numCIndices += dof;
85717c927364SMatthew G. Knepley   }
85727c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
85737c927364SMatthew G. Knepley   /* Row indices */
85749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8575412e9a14SMatthew G. Knepley   {
8576012bc364SMatthew G. Knepley     DMPlexTransform tr;
8577012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8578012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8579012bc364SMatthew G. Knepley 
85809566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
85819566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
85829566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8583012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
85849566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8585412e9a14SMatthew G. Knepley   }
85869566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
85877c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
85887c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
85899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
85907c927364SMatthew G. Knepley     /* Compress out points not in the section */
85919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
85927c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
85937c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
85949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
85957c927364SMatthew G. Knepley         if (!dof) continue;
85969371c9d4SSatish Balay         for (s = 0; s < q; ++s)
85979371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
85987c927364SMatthew G. Knepley         if (s < q) continue;
85997c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
86007c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
86017c927364SMatthew G. Knepley         ++q;
86027c927364SMatthew G. Knepley       }
86037c927364SMatthew G. Knepley     }
86049566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
86057c927364SMatthew G. Knepley   }
86067c927364SMatthew G. Knepley   numFPoints = q;
86077c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
86087c927364SMatthew G. Knepley     PetscInt fdof;
86097c927364SMatthew G. Knepley 
86109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
86117c927364SMatthew G. Knepley     if (!dof) continue;
86127c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
86139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
86147c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
86157c927364SMatthew G. Knepley     }
86167c927364SMatthew G. Knepley     numFIndices += dof;
86177c927364SMatthew G. Knepley   }
86187c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
86197c927364SMatthew G. Knepley 
86201dca8a05SBarry 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);
86211dca8a05SBarry 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);
86227c927364SMatthew G. Knepley   if (numFields) {
86234acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
86244acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
86254acb8e1eSToby Isaac 
86264acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
86279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
86289566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
86297c927364SMatthew G. Knepley     }
86304acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
86319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
86329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
86334acb8e1eSToby Isaac     }
86344acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
86359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
86369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
86374acb8e1eSToby Isaac     }
86384acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
86399566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
86409566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
86417c927364SMatthew G. Knepley     }
86427c927364SMatthew G. Knepley   } else {
86434acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
86444acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
86454acb8e1eSToby Isaac 
86469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
86479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
86484acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
86494acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
86504acb8e1eSToby Isaac 
86519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
86529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
86537c927364SMatthew G. Knepley     }
86544acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
86554acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
86564acb8e1eSToby Isaac 
86579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
86589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
86597c927364SMatthew G. Knepley     }
86609566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
86619566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
86627c927364SMatthew G. Knepley   }
86639566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
86649566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
86653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
86667c927364SMatthew G. Knepley }
86677c927364SMatthew G. Knepley 
8668cc4c1da9SBarry Smith /*@
86697cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
86707cd05799SMatthew G. Knepley 
86717cd05799SMatthew G. Knepley   Input Parameter:
8672a1cb98faSBarry Smith . dm - The `DMPLEX` object
86737cd05799SMatthew G. Knepley 
86747cd05799SMatthew G. Knepley   Output Parameter:
86757cd05799SMatthew G. Knepley . cellHeight - The height of a cell
86767cd05799SMatthew G. Knepley 
86777cd05799SMatthew G. Knepley   Level: developer
86787cd05799SMatthew G. Knepley 
86791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
86807cd05799SMatthew G. Knepley @*/
8681d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8682d71ae5a4SJacob Faibussowitsch {
8683552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8684552f7358SJed Brown 
8685552f7358SJed Brown   PetscFunctionBegin;
8686552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86874f572ea9SToby Isaac   PetscAssertPointer(cellHeight, 2);
8688552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
86893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8690552f7358SJed Brown }
8691552f7358SJed Brown 
8692cc4c1da9SBarry Smith /*@
86937cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
86947cd05799SMatthew G. Knepley 
86957cd05799SMatthew G. Knepley   Input Parameters:
8696a1cb98faSBarry Smith + dm         - The `DMPLEX` object
86977cd05799SMatthew G. Knepley - cellHeight - The height of a cell
86987cd05799SMatthew G. Knepley 
86997cd05799SMatthew G. Knepley   Level: developer
87007cd05799SMatthew G. Knepley 
87011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
87027cd05799SMatthew G. Knepley @*/
8703d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8704d71ae5a4SJacob Faibussowitsch {
8705552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8706552f7358SJed Brown 
8707552f7358SJed Brown   PetscFunctionBegin;
8708552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8709552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
87103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8711552f7358SJed Brown }
8712552f7358SJed Brown 
8713e6139122SMatthew G. Knepley /*@
87142827ebadSStefano Zampini   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8715e6139122SMatthew G. Knepley 
87162827ebadSStefano Zampini   Input Parameters:
87172827ebadSStefano Zampini + dm - The `DMPLEX` object
87182827ebadSStefano Zampini - ct - The `DMPolytopeType` of the cell
8719e6139122SMatthew G. Knepley 
8720e6139122SMatthew G. Knepley   Output Parameters:
87212827ebadSStefano Zampini + start - The first cell of this type, or `NULL`
87222827ebadSStefano Zampini - end   - The upper bound on this celltype, or `NULL`
8723e6139122SMatthew G. Knepley 
87242a9f31c0SMatthew G. Knepley   Level: advanced
8725e6139122SMatthew G. Knepley 
87262827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8727e6139122SMatthew G. Knepley @*/
87282827ebadSStefano Zampini PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end)
8729d71ae5a4SJacob Faibussowitsch {
87302827ebadSStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
87312827ebadSStefano Zampini   DMLabel  label;
87322827ebadSStefano Zampini   PetscInt pStart, pEnd;
8733e6139122SMatthew G. Knepley 
8734e6139122SMatthew G. Knepley   PetscFunctionBegin;
8735e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87362827ebadSStefano Zampini   if (start) {
87374f572ea9SToby Isaac     PetscAssertPointer(start, 3);
87382827ebadSStefano Zampini     *start = 0;
87392827ebadSStefano Zampini   }
87402827ebadSStefano Zampini   if (end) {
87414f572ea9SToby Isaac     PetscAssertPointer(end, 4);
87422827ebadSStefano Zampini     *end = 0;
87432827ebadSStefano Zampini   }
87442827ebadSStefano Zampini   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
87452827ebadSStefano Zampini   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
87462827ebadSStefano Zampini   if (mesh->tr) {
87472827ebadSStefano Zampini     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
87482827ebadSStefano Zampini   } else {
87492827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
87502827ebadSStefano Zampini     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
87512827ebadSStefano Zampini     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
87522827ebadSStefano Zampini   }
87533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8754e6139122SMatthew G. Knepley }
8755e6139122SMatthew G. Knepley 
8756d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8757d71ae5a4SJacob Faibussowitsch {
8758552f7358SJed Brown   PetscSection section, globalSection;
8759552f7358SJed Brown   PetscInt    *numbers, p;
8760552f7358SJed Brown 
8761552f7358SJed Brown   PetscFunctionBegin;
8762d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
87639566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
87649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
876548a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
87669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8767eb9d3e4dSMatthew G. Knepley   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection));
87689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8769552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
87709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8771ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
8772ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
8773552f7358SJed Brown   }
87749566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8775ef48cebcSMatthew G. Knepley   if (globalSize) {
8776ef48cebcSMatthew G. Knepley     PetscLayout layout;
87779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
87789566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
87799566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8780ef48cebcSMatthew G. Knepley   }
87819566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
87829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
87833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8784552f7358SJed Brown }
8785552f7358SJed Brown 
8786e2b8d0fcSMatthew G. Knepley /*@
8787e2b8d0fcSMatthew G. Knepley   DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process
8788e2b8d0fcSMatthew G. Knepley 
8789bc9da2b0SJose E. Roman   Input Parameters:
8790e2b8d0fcSMatthew G. Knepley + dm         - The `DMPLEX` object
8791e2b8d0fcSMatthew G. Knepley - includeAll - Whether to include all cells, or just the simplex and box cells
8792e2b8d0fcSMatthew G. Knepley 
8793e2b8d0fcSMatthew G. Knepley   Output Parameter:
8794e2b8d0fcSMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
8795e2b8d0fcSMatthew G. Knepley 
8796e2b8d0fcSMatthew G. Knepley   Level: developer
8797e2b8d0fcSMatthew G. Knepley 
8798e2b8d0fcSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`
8799e2b8d0fcSMatthew G. Knepley @*/
8800e2b8d0fcSMatthew G. Knepley PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers)
8801d71ae5a4SJacob Faibussowitsch {
8802412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
8803552f7358SJed Brown 
8804552f7358SJed Brown   PetscFunctionBegin;
88059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
8806e2b8d0fcSMatthew G. Knepley   if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
88079566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
88089566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
88093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8810552f7358SJed Brown }
881181ed3555SMatthew G. Knepley 
88128dab3259SMatthew G. Knepley /*@
88137cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
88147cd05799SMatthew G. Knepley 
88157cd05799SMatthew G. Knepley   Input Parameter:
8816a1cb98faSBarry Smith . dm - The `DMPLEX` object
88177cd05799SMatthew G. Knepley 
88187cd05799SMatthew G. Knepley   Output Parameter:
88197cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
88207cd05799SMatthew G. Knepley 
88217cd05799SMatthew G. Knepley   Level: developer
88227cd05799SMatthew G. Knepley 
8823e2b8d0fcSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()`
88247cd05799SMatthew G. Knepley @*/
8825d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8826d71ae5a4SJacob Faibussowitsch {
882781ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
882881ed3555SMatthew G. Knepley 
882981ed3555SMatthew G. Knepley   PetscFunctionBegin;
883081ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8831e2b8d0fcSMatthew G. Knepley   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8832552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
88333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8834552f7358SJed Brown }
8835552f7358SJed Brown 
8836d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8837d71ae5a4SJacob Faibussowitsch {
8838412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
883981ed3555SMatthew G. Knepley 
884081ed3555SMatthew G. Knepley   PetscFunctionBegin;
884181ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
88439566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
88443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
884581ed3555SMatthew G. Knepley }
884681ed3555SMatthew G. Knepley 
88478dab3259SMatthew G. Knepley /*@
88486aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
88497cd05799SMatthew G. Knepley 
88507cd05799SMatthew G. Knepley   Input Parameter:
8851a1cb98faSBarry Smith . dm - The `DMPLEX` object
88527cd05799SMatthew G. Knepley 
88537cd05799SMatthew G. Knepley   Output Parameter:
88547cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
88557cd05799SMatthew G. Knepley 
88567cd05799SMatthew G. Knepley   Level: developer
88577cd05799SMatthew G. Knepley 
88581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
88597cd05799SMatthew G. Knepley @*/
8860d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8861d71ae5a4SJacob Faibussowitsch {
8862552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8863552f7358SJed Brown 
8864552f7358SJed Brown   PetscFunctionBegin;
8865552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88669566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8867552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
88683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8869552f7358SJed Brown }
8870552f7358SJed Brown 
88718dab3259SMatthew G. Knepley /*@
8872966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
8873966484cfSJed Brown 
887420f4b53cSBarry Smith   Collective
88757cd05799SMatthew G. Knepley 
88767cd05799SMatthew G. Knepley   Input Parameter:
8877a1cb98faSBarry Smith . dm - The `DMPLEX` object
88787cd05799SMatthew G. Knepley 
88797cd05799SMatthew G. Knepley   Output Parameter:
88807cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
88817cd05799SMatthew G. Knepley 
8882a1cb98faSBarry Smith   Level: developer
8883966484cfSJed Brown 
8884a1cb98faSBarry Smith   Notes:
8885a1cb98faSBarry Smith   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
8886966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
8887966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
8888966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
8889966484cfSJed Brown 
8890966484cfSJed Brown   The partitioned mesh is
8891966484cfSJed Brown   ```
8892966484cfSJed Brown   (2)--0--(3)--1--(4)    (1)--0--(2)
8893966484cfSJed Brown   ```
8894966484cfSJed Brown   and its global numbering is
8895966484cfSJed Brown   ```
8896966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
8897966484cfSJed Brown   ```
8898966484cfSJed Brown   Then the global numbering is provided as
8899966484cfSJed Brown   ```
8900966484cfSJed Brown   [0] Number of indices in set 5
8901966484cfSJed Brown   [0] 0 0
8902966484cfSJed Brown   [0] 1 1
8903966484cfSJed Brown   [0] 2 3
8904966484cfSJed Brown   [0] 3 4
8905966484cfSJed Brown   [0] 4 -6
8906966484cfSJed Brown   [1] Number of indices in set 3
8907966484cfSJed Brown   [1] 0 2
8908966484cfSJed Brown   [1] 1 5
8909966484cfSJed Brown   [1] 2 6
8910966484cfSJed Brown   ```
8911966484cfSJed Brown 
89121cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
89137cd05799SMatthew G. Knepley @*/
8914d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8915d71ae5a4SJacob Faibussowitsch {
8916ef48cebcSMatthew G. Knepley   IS        nums[4];
8917862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
8918ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
89190c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
8920ef48cebcSMatthew G. Knepley 
8921ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8922ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
89240c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
89259566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
89260c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
8927862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8928862913ffSStefano Zampini     PetscInt end;
8929862913ffSStefano Zampini 
8930862913ffSStefano Zampini     depths[d] = depth - d;
89319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
89320c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
8933862913ffSStefano Zampini   }
89340c15888dSMatthew G. Knepley   if (empty)
89350c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
89360c15888dSMatthew G. Knepley       depths[d] = -1;
89370c15888dSMatthew G. Knepley       starts[d] = -1;
89380c15888dSMatthew G. Knepley     }
89390c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
8940*6497c311SBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, (PetscMPIInt)(depth + 1), MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
8941ad540459SPierre 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]);
89420c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
8943ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8944ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8945ef48cebcSMatthew G. Knepley 
89469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
89479566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8948ef48cebcSMatthew G. Knepley     shift += gsize;
8949ef48cebcSMatthew G. Knepley   }
8950d1c35871SJed Brown   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
89519566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
89523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8953ef48cebcSMatthew G. Knepley }
8954ef48cebcSMatthew G. Knepley 
895508a22f4bSMatthew G. Knepley /*@
8956484edb7dSMatthew G. Knepley   DMPlexCreateEdgeNumbering - Create a global numbering for edges.
8957484edb7dSMatthew G. Knepley 
8958484edb7dSMatthew G. Knepley   Collective
8959484edb7dSMatthew G. Knepley 
8960484edb7dSMatthew G. Knepley   Input Parameter:
8961484edb7dSMatthew G. Knepley . dm - The `DMPLEX` object
8962484edb7dSMatthew G. Knepley 
8963484edb7dSMatthew G. Knepley   Output Parameter:
8964484edb7dSMatthew G. Knepley . globalEdgeNumbers - Global numbers for all edges on this process
8965484edb7dSMatthew G. Knepley 
8966484edb7dSMatthew G. Knepley   Level: developer
8967484edb7dSMatthew G. Knepley 
8968484edb7dSMatthew G. Knepley   Notes:
8969484edb7dSMatthew 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).
8970484edb7dSMatthew G. Knepley 
8971484edb7dSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()`
8972484edb7dSMatthew G. Knepley @*/
8973484edb7dSMatthew G. Knepley PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers)
8974484edb7dSMatthew G. Knepley {
8975484edb7dSMatthew G. Knepley   PetscSF  sf;
8976484edb7dSMatthew G. Knepley   PetscInt eStart, eEnd;
8977484edb7dSMatthew G. Knepley 
8978484edb7dSMatthew G. Knepley   PetscFunctionBegin;
8979484edb7dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8980484edb7dSMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
8981484edb7dSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
8982484edb7dSMatthew G. Knepley   PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers));
8983484edb7dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
8984484edb7dSMatthew G. Knepley }
8985484edb7dSMatthew G. Knepley 
8986484edb7dSMatthew G. Knepley /*@
898708a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
898808a22f4bSMatthew G. Knepley 
898908a22f4bSMatthew G. Knepley   Input Parameter:
8990a1cb98faSBarry Smith . dm - The `DMPLEX` object
899108a22f4bSMatthew G. Knepley 
899208a22f4bSMatthew G. Knepley   Output Parameter:
899308a22f4bSMatthew G. Knepley . ranks - The rank field
899408a22f4bSMatthew G. Knepley 
8995a1cb98faSBarry Smith   Options Database Key:
899620f4b53cSBarry Smith . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
899708a22f4bSMatthew G. Knepley 
899808a22f4bSMatthew G. Knepley   Level: intermediate
899908a22f4bSMatthew G. Knepley 
90001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
900108a22f4bSMatthew G. Knepley @*/
9002d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
9003d71ae5a4SJacob Faibussowitsch {
900408a22f4bSMatthew G. Knepley   DM             rdm;
900508a22f4bSMatthew G. Knepley   PetscFE        fe;
900608a22f4bSMatthew G. Knepley   PetscScalar   *r;
900708a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
9008a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
900908a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
9010a55f9a55SMatthew G. Knepley   PetscBool      simplex;
901108a22f4bSMatthew G. Knepley 
901208a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
9013f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90144f572ea9SToby Isaac   PetscAssertPointer(ranks, 2);
90159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
90169566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
90179566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
90189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
90199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9020a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
90219566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
90229566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
90239566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
90249566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
90259566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
90269566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
90279566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
90289566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
902908a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
903008a22f4bSMatthew G. Knepley     PetscScalar *lr;
903108a22f4bSMatthew G. Knepley 
90329566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
903371f09efeSPierre Jolivet     if (lr) *lr = rank;
903408a22f4bSMatthew G. Knepley   }
90359566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
90369566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
90373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
903808a22f4bSMatthew G. Knepley }
903908a22f4bSMatthew G. Knepley 
9040ca8062c8SMatthew G. Knepley /*@
9041acf3173eSStefano Zampini   DMPlexCreateLabelField - Create a field whose value is the label value for that point
904218e14f0cSMatthew G. Knepley 
904318e14f0cSMatthew G. Knepley   Input Parameters:
904420f4b53cSBarry Smith + dm    - The `DMPLEX`
904520f4b53cSBarry Smith - label - The `DMLabel`
904618e14f0cSMatthew G. Knepley 
904718e14f0cSMatthew G. Knepley   Output Parameter:
904818e14f0cSMatthew G. Knepley . val - The label value field
904918e14f0cSMatthew G. Knepley 
905020f4b53cSBarry Smith   Options Database Key:
905120f4b53cSBarry Smith . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
905218e14f0cSMatthew G. Knepley 
905318e14f0cSMatthew G. Knepley   Level: intermediate
905418e14f0cSMatthew G. Knepley 
90551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
905618e14f0cSMatthew G. Knepley @*/
9057d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
9058d71ae5a4SJacob Faibussowitsch {
90591033741fSStefano Zampini   DM             rdm, plex;
9060acf3173eSStefano Zampini   Vec            lval;
9061acf3173eSStefano Zampini   PetscSection   section;
906218e14f0cSMatthew G. Knepley   PetscFE        fe;
906318e14f0cSMatthew G. Knepley   PetscScalar   *v;
9064acf3173eSStefano Zampini   PetscInt       dim, pStart, pEnd, p, cStart;
9065acf3173eSStefano Zampini   DMPolytopeType ct;
9066acf3173eSStefano Zampini   char           name[PETSC_MAX_PATH_LEN];
9067acf3173eSStefano Zampini   const char    *lname, *prefix;
906818e14f0cSMatthew G. Knepley 
906918e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
907018e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90714f572ea9SToby Isaac   PetscAssertPointer(label, 2);
90724f572ea9SToby Isaac   PetscAssertPointer(val, 3);
90739566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
9074acf3173eSStefano Zampini   PetscCall(DMConvert(rdm, DMPLEX, &plex));
9075acf3173eSStefano Zampini   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL));
9076acf3173eSStefano Zampini   PetscCall(DMPlexGetCellType(plex, cStart, &ct));
9077acf3173eSStefano Zampini   PetscCall(DMDestroy(&plex));
90789566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
9079acf3173eSStefano Zampini   PetscCall(DMGetOptionsPrefix(dm, &prefix));
9080acf3173eSStefano Zampini   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
9081acf3173eSStefano Zampini   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname));
9082acf3173eSStefano Zampini   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe));
9083acf3173eSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)fe, ""));
90849566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
90859566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
90869566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
90879566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
9088acf3173eSStefano Zampini   PetscCall(DMCreateLocalVector(rdm, &lval));
9089acf3173eSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)*val, lname));
9090acf3173eSStefano Zampini   PetscCall(DMGetLocalSection(rdm, &section));
9091acf3173eSStefano Zampini   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
9092acf3173eSStefano Zampini   PetscCall(VecGetArray(lval, &v));
9093acf3173eSStefano Zampini   for (p = pStart; p < pEnd; ++p) {
9094acf3173eSStefano Zampini     PetscInt cval, dof, off;
909518e14f0cSMatthew G. Knepley 
9096acf3173eSStefano Zampini     PetscCall(PetscSectionGetDof(section, p, &dof));
9097acf3173eSStefano Zampini     if (!dof) continue;
9098acf3173eSStefano Zampini     PetscCall(DMLabelGetValue(label, p, &cval));
9099acf3173eSStefano Zampini     PetscCall(PetscSectionGetOffset(section, p, &off));
9100acf3173eSStefano Zampini     for (PetscInt d = 0; d < dof; d++) v[off + d] = cval;
910118e14f0cSMatthew G. Knepley   }
9102acf3173eSStefano Zampini   PetscCall(VecRestoreArray(lval, &v));
9103acf3173eSStefano Zampini   PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val));
9104acf3173eSStefano Zampini   PetscCall(VecDestroy(&lval));
91059566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
91063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
910718e14f0cSMatthew G. Knepley }
910818e14f0cSMatthew G. Knepley 
910918e14f0cSMatthew G. Knepley /*@
9110ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
9111ca8062c8SMatthew G. Knepley 
911269916449SMatthew G. Knepley   Input Parameter:
9113a1cb98faSBarry Smith . dm - The `DMPLEX` object
9114a1cb98faSBarry Smith 
9115a1cb98faSBarry Smith   Level: developer
9116ca8062c8SMatthew G. Knepley 
911795eb5ee5SVaclav Hapla   Notes:
911895eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
911995eb5ee5SVaclav Hapla 
912020f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9121ca8062c8SMatthew G. Knepley 
91221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9123ca8062c8SMatthew G. Knepley @*/
9124d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
9125d71ae5a4SJacob Faibussowitsch {
9126ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
9127ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
9128ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
912957beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
913057beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
9131ca8062c8SMatthew G. Knepley 
9132ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9133ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91349566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
91359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
91369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
9137ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
91389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9139ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
91409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
91419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
9142ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
914342e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
914442e66dfaSMatthew G. Knepley       PetscInt  d;
914542e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
91469371c9d4SSatish Balay         if (cone[c] == cone[d]) {
91479371c9d4SSatish Balay           dup = PETSC_TRUE;
91489371c9d4SSatish Balay           break;
91499371c9d4SSatish Balay         }
915042e66dfaSMatthew G. Knepley       }
91519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
91529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
9153ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
9154ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
9155ca8062c8SMatthew G. Knepley       }
915642e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
915763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
915848a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
91599566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
916063a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
916148a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
91629566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
916363a3b9bcSJacob 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]);
9164f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
9165ca8062c8SMatthew G. Knepley       }
916642e66dfaSMatthew G. Knepley     }
91679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
91689371c9d4SSatish Balay     if (p != pp) {
91699371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
91709371c9d4SSatish Balay       continue;
91719371c9d4SSatish Balay     }
91729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
91739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
9174ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
91759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
91769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
9177ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
91789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
91799371c9d4SSatish Balay         if (cone[c] != pp) {
91809371c9d4SSatish Balay           c = 0;
91819371c9d4SSatish Balay           break;
91829371c9d4SSatish Balay         }
9183ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
9184ca8062c8SMatthew G. Knepley       }
9185ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
918663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
918748a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
91889566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
918963a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
919048a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
91919566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
919263a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
9193ca8062c8SMatthew G. Knepley       }
9194ca8062c8SMatthew G. Knepley     }
9195ca8062c8SMatthew G. Knepley   }
919657beb4faSStefano Zampini   if (storagecheck) {
91979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
91989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
919963a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
920057beb4faSStefano Zampini   }
92013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9202ca8062c8SMatthew G. Knepley }
9203ca8062c8SMatthew G. Knepley 
9204412e9a14SMatthew G. Knepley /*
9205412e9a14SMatthew 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.
9206412e9a14SMatthew G. Knepley */
9207d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
9208d71ae5a4SJacob Faibussowitsch {
9209412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
9210412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
9211412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
9212412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
9213412e9a14SMatthew G. Knepley 
9214412e9a14SMatthew G. Knepley   PetscFunctionBegin;
9215412e9a14SMatthew G. Knepley   *unsplit = 0;
9216412e9a14SMatthew G. Knepley   switch (ct) {
9217d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
9218d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
9219d71ae5a4SJacob Faibussowitsch     break;
9220412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
92219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
92229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9223412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
92249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
9225412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
9226412e9a14SMatthew G. Knepley     }
9227412e9a14SMatthew G. Knepley     break;
9228412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
9229412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
92309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
92319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9232412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
92339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
92349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
9235412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
92369566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
9237412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
9238412e9a14SMatthew G. Knepley           PetscInt p;
92399371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
92409371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
9241412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
9242412e9a14SMatthew G. Knepley         }
9243412e9a14SMatthew G. Knepley       }
9244412e9a14SMatthew G. Knepley     }
9245412e9a14SMatthew G. Knepley     break;
9246d71ae5a4SJacob Faibussowitsch   default:
9247d71ae5a4SJacob Faibussowitsch     break;
9248412e9a14SMatthew G. Knepley   }
9249412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
92509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
9251412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
9252412e9a14SMatthew G. Knepley   }
92533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9254412e9a14SMatthew G. Knepley }
9255412e9a14SMatthew G. Knepley 
9256ca8062c8SMatthew G. Knepley /*@
9257ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
9258ca8062c8SMatthew G. Knepley 
9259ca8062c8SMatthew G. Knepley   Input Parameters:
9260a1cb98faSBarry Smith + dm         - The `DMPLEX` object
926158723a97SMatthew G. Knepley - cellHeight - Normally 0
9262ca8062c8SMatthew G. Knepley 
9263a1cb98faSBarry Smith   Level: developer
9264a1cb98faSBarry Smith 
926595eb5ee5SVaclav Hapla   Notes:
926695eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
926725c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
9268ca8062c8SMatthew G. Knepley 
926920f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
927095eb5ee5SVaclav Hapla 
92711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9272ca8062c8SMatthew G. Knepley @*/
9273d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
9274d71ae5a4SJacob Faibussowitsch {
9275412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
9276412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
9277412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
9278ca8062c8SMatthew G. Knepley 
9279ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9280ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
92819566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
92829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
92839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9284412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9285412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
9286412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
928758723a97SMatthew G. Knepley 
92889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9289412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
9290412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
92919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
929263a3b9bcSJacob 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));
9293412e9a14SMatthew G. Knepley     }
92949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
929558723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
929658723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
9297412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
929858723a97SMatthew G. Knepley     }
92999566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9300412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
9301412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
9302412e9a14SMatthew G. Knepley       PetscInt unsplit;
930342363296SMatthew G. Knepley 
93049566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9305412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
930642363296SMatthew G. Knepley     }
930763a3b9bcSJacob 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));
930842363296SMatthew G. Knepley   }
93093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9310ca8062c8SMatthew G. Knepley }
93119bf0dad6SMatthew G. Knepley 
93129bf0dad6SMatthew G. Knepley /*@
93139bf0dad6SMatthew 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
93149bf0dad6SMatthew G. Knepley 
931520f4b53cSBarry Smith   Collective
9316899ea2b8SJacob Faibussowitsch 
93179bf0dad6SMatthew G. Knepley   Input Parameters:
9318a1cb98faSBarry Smith + dm         - The `DMPLEX` object
93199bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
93209bf0dad6SMatthew G. Knepley 
9321a1cb98faSBarry Smith   Level: developer
9322a1cb98faSBarry Smith 
932345da879fSVaclav Hapla   Notes:
932445da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
932545da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
932645da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
932745da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
93289bf0dad6SMatthew G. Knepley 
9329a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
933095eb5ee5SVaclav Hapla 
93311cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
93329bf0dad6SMatthew G. Knepley @*/
9333d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
9334d71ae5a4SJacob Faibussowitsch {
9335ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
9336899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
93379bf0dad6SMatthew G. Knepley 
93389bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
93399bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93408f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
93413ba16761SJacob Faibussowitsch   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
93428f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
93433ba16761SJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
93443ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
9345899ea2b8SJacob Faibussowitsch   }
9346899ea2b8SJacob Faibussowitsch 
93479566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
93489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
93499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9350ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
93519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
93523554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
9353412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
9354412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
9355ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
9356412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
9357412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
93589bf0dad6SMatthew G. Knepley 
93599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
93609566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9361412e9a14SMatthew G. Knepley       if (unsplit) continue;
93629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
93639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
93649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
93659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
93669bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
93679bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
93689bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
93699bf0dad6SMatthew G. Knepley       }
93709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
937163a3b9bcSJacob 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);
93729bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
9373d4961f80SStefano Zampini         DMPolytopeType fct;
93749bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
93759bf0dad6SMatthew G. Knepley 
93769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
93779566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
93789bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
93799bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
93809bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
93819bf0dad6SMatthew G. Knepley         }
938263a3b9bcSJacob 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]);
93839bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
9384b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
9385b5a892a1SMatthew G. Knepley             PetscInt v1;
9386b5a892a1SMatthew G. Knepley 
93879566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
938863a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
93899566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
939063a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
93919566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
939263a3b9bcSJacob 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]);
9393b5a892a1SMatthew G. Knepley           }
93949bf0dad6SMatthew G. Knepley         }
93959566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
9396412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
93979bf0dad6SMatthew G. Knepley       }
93989566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
93999566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
94009bf0dad6SMatthew G. Knepley     }
94013554e41dSMatthew G. Knepley   }
94023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9403552f7358SJed Brown }
94043913d7c8SMatthew G. Knepley 
9405bb6a34a8SMatthew G. Knepley /*@
9406bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
9407bb6a34a8SMatthew G. Knepley 
9408bb6a34a8SMatthew G. Knepley   Input Parameter:
9409a1cb98faSBarry Smith . dm - The `DMPLEX` object
9410a1cb98faSBarry Smith 
9411a1cb98faSBarry Smith   Level: developer
9412bb6a34a8SMatthew G. Knepley 
941395eb5ee5SVaclav Hapla   Notes:
941495eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
941595eb5ee5SVaclav Hapla 
941620f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9417bb6a34a8SMatthew G. Knepley 
94181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9419bb6a34a8SMatthew G. Knepley @*/
9420d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
9421d71ae5a4SJacob Faibussowitsch {
9422a2a9e04cSMatthew G. Knepley   Vec       coordinates;
9423bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
9424bb6a34a8SMatthew G. Knepley   PetscReal vol;
942551a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9426bb6a34a8SMatthew G. Knepley 
9427bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
94289566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
94299566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
94303ba16761SJacob Faibussowitsch   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
94319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
9432bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
94339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9434a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
94359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
94363ba16761SJacob Faibussowitsch   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9437412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9438412e9a14SMatthew G. Knepley     DMPolytopeType ct;
9439412e9a14SMatthew G. Knepley     PetscInt       unsplit;
9440412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
9441412e9a14SMatthew G. Knepley 
94429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9443412e9a14SMatthew G. Knepley     switch (ct) {
9444412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9445412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9446d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9447d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
9448d71ae5a4SJacob Faibussowitsch       break;
9449d71ae5a4SJacob Faibussowitsch     default:
9450d71ae5a4SJacob Faibussowitsch       break;
9451412e9a14SMatthew G. Knepley     }
9452412e9a14SMatthew G. Knepley     switch (ct) {
9453412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
9454412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9455412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9456d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
9457d71ae5a4SJacob Faibussowitsch       continue;
9458d71ae5a4SJacob Faibussowitsch     default:
9459d71ae5a4SJacob Faibussowitsch       break;
9460412e9a14SMatthew G. Knepley     }
94619566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9462412e9a14SMatthew G. Knepley     if (unsplit) continue;
94639566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
94641dca8a05SBarry 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);
946563a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
94666858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
94676858538eSMatthew G. Knepley     if (depth > 1) {
94689566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
94691dca8a05SBarry 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);
947063a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9471bb6a34a8SMatthew G. Knepley     }
9472bb6a34a8SMatthew G. Knepley   }
94733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9474bb6a34a8SMatthew G. Knepley }
9475bb6a34a8SMatthew G. Knepley 
947603da9461SVaclav Hapla /*@
947720f4b53cSBarry Smith   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
94787726db96SVaclav Hapla 
947920f4b53cSBarry Smith   Collective
948003da9461SVaclav Hapla 
948103da9461SVaclav Hapla   Input Parameters:
9482a1cb98faSBarry Smith + dm              - The `DMPLEX` object
948320f4b53cSBarry Smith . pointSF         - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9484a1cb98faSBarry Smith - allowExtraRoots - Flag to allow extra points not present in the `DM`
9485a1cb98faSBarry Smith 
9486a1cb98faSBarry Smith   Level: developer
948703da9461SVaclav Hapla 
9488e83a0d2dSVaclav Hapla   Notes:
9489e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
949003da9461SVaclav Hapla 
9491a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
949295eb5ee5SVaclav Hapla 
9493baca6076SPierre Jolivet   Extra roots can come from periodic cuts, where additional points appear on the boundary
9494d7d32a9aSMatthew G. Knepley 
94951cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
949603da9461SVaclav Hapla @*/
9497d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9498d71ae5a4SJacob Faibussowitsch {
94997726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
95007726db96SVaclav Hapla   const PetscInt    *locals;
95017726db96SVaclav Hapla   const PetscSFNode *remotes;
9502f0cfc026SVaclav Hapla   PetscBool          distributed;
95037726db96SVaclav Hapla   MPI_Comm           comm;
95047726db96SVaclav Hapla   PetscMPIInt        rank;
950503da9461SVaclav Hapla 
950603da9461SVaclav Hapla   PetscFunctionBegin;
950703da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95087726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
95097726db96SVaclav Hapla   else pointSF = dm->sf;
95107726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
95117726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
95127726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
95137726db96SVaclav Hapla   {
95147726db96SVaclav Hapla     PetscMPIInt mpiFlag;
95157726db96SVaclav Hapla 
95167726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
95177726db96SVaclav 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);
95187726db96SVaclav Hapla   }
95197726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
95209566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
95217726db96SVaclav Hapla   if (!distributed) {
95227726db96SVaclav 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);
95233ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
95248918e3e2SVaclav Hapla   }
95257726db96SVaclav 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);
95267726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
952703da9461SVaclav Hapla 
95287726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
95297726db96SVaclav Hapla   {
95307726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
95317726db96SVaclav Hapla 
95327726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
95337726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9534d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
95357726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
95367726db96SVaclav Hapla   }
95377726db96SVaclav Hapla 
95387726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
95397726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
9540*6497c311SBarry Smith     PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, (PetscMPIInt)remotes[l].rank, remotes[l].index);
95417726db96SVaclav Hapla   }
95427726db96SVaclav Hapla 
95437726db96SVaclav Hapla   /* Check there are no cells in interface */
95447726db96SVaclav Hapla   if (!overlap) {
95457726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
95467726db96SVaclav Hapla 
95479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
95489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9549f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
95507726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
9551f5869d18SMatthew G. Knepley 
95527726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
95537726db96SVaclav Hapla     }
955403da9461SVaclav Hapla   }
9555ece87651SVaclav Hapla 
95567726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
95577726db96SVaclav Hapla   {
95587726db96SVaclav Hapla     const PetscInt *rootdegree;
95597726db96SVaclav Hapla 
95607726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
95617726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9562f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
95637726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9564f5869d18SMatthew G. Knepley       const PetscInt *cone;
9565f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9566f5869d18SMatthew G. Knepley 
95679566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
95689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9569f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9570f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
95717726db96SVaclav Hapla           if (locals) {
95729566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
95737726db96SVaclav Hapla           } else {
95747726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
95757726db96SVaclav Hapla           }
957663a3b9bcSJacob 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]);
9577f5869d18SMatthew G. Knepley         }
9578f5869d18SMatthew G. Knepley       }
9579ece87651SVaclav Hapla     }
95807726db96SVaclav Hapla   }
95813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
958203da9461SVaclav Hapla }
958303da9461SVaclav Hapla 
95847f9d8d6cSVaclav Hapla /*@
9585217fe35eSMatthew G. Knepley   DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices.
9586217fe35eSMatthew G. Knepley 
9587217fe35eSMatthew G. Knepley   Collective
9588217fe35eSMatthew G. Knepley 
9589217fe35eSMatthew G. Knepley   Input Parameter:
9590217fe35eSMatthew G. Knepley . dm - The `DMPLEX` object
9591217fe35eSMatthew G. Knepley 
9592217fe35eSMatthew G. Knepley   Level: developer
9593217fe35eSMatthew G. Knepley 
9594217fe35eSMatthew G. Knepley   Notes:
9595217fe35eSMatthew G. Knepley   This is mainly intended for debugging/testing purposes.
9596217fe35eSMatthew G. Knepley 
9597217fe35eSMatthew G. Knepley   Other cell types which are disconnected would be caught by the symmetry and face checks.
9598217fe35eSMatthew G. Knepley 
9599217fe35eSMatthew G. Knepley   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9600217fe35eSMatthew G. Knepley 
9601217fe35eSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()`
9602217fe35eSMatthew G. Knepley @*/
9603217fe35eSMatthew G. Knepley PetscErrorCode DMPlexCheckOrphanVertices(DM dm)
9604217fe35eSMatthew G. Knepley {
9605217fe35eSMatthew G. Knepley   PetscInt pStart, pEnd, vStart, vEnd;
9606217fe35eSMatthew G. Knepley 
9607217fe35eSMatthew G. Knepley   PetscFunctionBegin;
9608217fe35eSMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9609217fe35eSMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9610217fe35eSMatthew G. Knepley   if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS);
9611217fe35eSMatthew G. Knepley   for (PetscInt v = vStart; v < vEnd; ++v) {
9612217fe35eSMatthew G. Knepley     PetscInt suppSize;
9613217fe35eSMatthew G. Knepley 
9614217fe35eSMatthew G. Knepley     PetscCall(DMPlexGetSupportSize(dm, v, &suppSize));
9615217fe35eSMatthew G. Knepley     PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v);
9616217fe35eSMatthew G. Knepley   }
9617217fe35eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9618217fe35eSMatthew G. Knepley }
9619217fe35eSMatthew G. Knepley 
9620217fe35eSMatthew G. Knepley /*@
962120f4b53cSBarry Smith   DMPlexCheck - Perform various checks of `DMPLEX` sanity
96227f9d8d6cSVaclav Hapla 
96237f9d8d6cSVaclav Hapla   Input Parameter:
9624a1cb98faSBarry Smith . dm - The `DMPLEX` object
9625a1cb98faSBarry Smith 
9626a1cb98faSBarry Smith   Level: developer
96277f9d8d6cSVaclav Hapla 
96287f9d8d6cSVaclav Hapla   Notes:
96297f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
96307f9d8d6cSVaclav Hapla 
963120f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
96327f9d8d6cSVaclav Hapla 
963320f4b53cSBarry Smith   Currently does not include `DMPlexCheckCellShape()`.
96347f9d8d6cSVaclav Hapla 
96351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
96367f9d8d6cSVaclav Hapla @*/
9637d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9638d71ae5a4SJacob Faibussowitsch {
96397f9d8d6cSVaclav Hapla   PetscInt cellHeight;
96407f9d8d6cSVaclav Hapla 
9641b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
96427f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
96439566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
96449566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
96459566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
96469566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9647d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
96489566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
9649217fe35eSMatthew G. Knepley   PetscCall(DMPlexCheckOrphanVertices(dm));
96503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9651b5a892a1SMatthew G. Knepley }
9652b5a892a1SMatthew G. Knepley 
96539371c9d4SSatish Balay typedef struct cell_stats {
9654068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9655068a5610SStefano Zampini   PetscInt  count;
9656068a5610SStefano Zampini } cell_stats_t;
9657068a5610SStefano Zampini 
9658d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9659d71ae5a4SJacob Faibussowitsch {
9660068a5610SStefano Zampini   PetscInt i, N = *len;
9661068a5610SStefano Zampini 
9662068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9663068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9664068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9665068a5610SStefano Zampini 
9666068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9667068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9668068a5610SStefano Zampini     B->sum += A->sum;
9669068a5610SStefano Zampini     B->squaresum += A->squaresum;
9670068a5610SStefano Zampini     B->count += A->count;
9671068a5610SStefano Zampini   }
9672068a5610SStefano Zampini }
9673068a5610SStefano Zampini 
9674068a5610SStefano Zampini /*@
967543fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9676068a5610SStefano Zampini 
967720f4b53cSBarry Smith   Collective
96788261a58bSMatthew G. Knepley 
9679068a5610SStefano Zampini   Input Parameters:
9680a1cb98faSBarry Smith + dm        - The `DMPLEX` object
968120f4b53cSBarry Smith . output    - If true, statistics will be displayed on `stdout`
9682a1cb98faSBarry Smith - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9683a1cb98faSBarry Smith 
9684a1cb98faSBarry Smith   Level: developer
9685068a5610SStefano Zampini 
968695eb5ee5SVaclav Hapla   Notes:
968795eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
968895eb5ee5SVaclav Hapla 
9689a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9690068a5610SStefano Zampini 
96911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9692068a5610SStefano Zampini @*/
9693d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9694d71ae5a4SJacob Faibussowitsch {
9695068a5610SStefano Zampini   DM           dmCoarse;
969643fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
969743fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
969843fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
969943fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9700412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
970143fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9702068a5610SStefano Zampini 
9703068a5610SStefano Zampini   PetscFunctionBegin;
9704068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9705068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9706068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9707068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9708068a5610SStefano Zampini   stats.count                 = 0;
9709068a5610SStefano Zampini 
97109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
97119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
97129566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
97139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
97149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
97159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9716412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9717068a5610SStefano Zampini     PetscInt  i;
9718068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9719068a5610SStefano Zampini 
97209566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
972163a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
972243fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9723068a5610SStefano Zampini       frobJ += J[i] * J[i];
9724068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9725068a5610SStefano Zampini     }
9726068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9727068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9728068a5610SStefano Zampini 
9729068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9730068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9731068a5610SStefano Zampini     stats.sum += cond;
9732068a5610SStefano Zampini     stats.squaresum += cond2;
9733068a5610SStefano Zampini     stats.count++;
97348261a58bSMatthew G. Knepley     if (output && cond > limit) {
973543fa8764SMatthew G. Knepley       PetscSection coordSection;
973643fa8764SMatthew G. Knepley       Vec          coordsLocal;
973743fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
973843fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
973943fa8764SMatthew G. Knepley 
97409566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
97419566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
97429566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
974363a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
974443fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
974563a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
974643fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
97479566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
97489566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
974943fa8764SMatthew G. Knepley         }
97509566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
975143fa8764SMatthew G. Knepley       }
97529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
975343fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
975443fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
975543fa8764SMatthew G. Knepley 
975643fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
975743fa8764SMatthew G. Knepley           PetscReal len;
975843fa8764SMatthew G. Knepley 
97599566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
976063a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
976143fa8764SMatthew G. Knepley         }
976243fa8764SMatthew G. Knepley       }
97639566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
97649566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
976543fa8764SMatthew G. Knepley     }
9766068a5610SStefano Zampini   }
97679566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9768068a5610SStefano Zampini 
9769068a5610SStefano Zampini   if (size > 1) {
9770068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9771068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9772068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9773068a5610SStefano Zampini     MPI_Op       statReduce;
9774068a5610SStefano Zampini 
97759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
97769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
97779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
97789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
97799566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
97809566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
9781068a5610SStefano Zampini   } else {
97829566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
9783068a5610SStefano Zampini   }
9784dd400576SPatrick Sanan   if (rank == 0) {
9785068a5610SStefano Zampini     count = globalStats.count;
9786068a5610SStefano Zampini     min   = globalStats.min;
9787068a5610SStefano Zampini     max   = globalStats.max;
9788068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
9789068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
9790068a5610SStefano Zampini   }
9791068a5610SStefano Zampini 
979248a46eb9SPierre 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));
97939566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
9794068a5610SStefano Zampini 
97959566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
9796068a5610SStefano Zampini   if (dmCoarse) {
9797068a5610SStefano Zampini     PetscBool isplex;
9798068a5610SStefano Zampini 
97999566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
98001baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
9801068a5610SStefano Zampini   }
98023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9803068a5610SStefano Zampini }
9804068a5610SStefano Zampini 
9805f108dbd7SJacob Faibussowitsch /*@
9806f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
9807f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
9808f108dbd7SJacob Faibussowitsch 
980920f4b53cSBarry Smith   Collective
9810f108dbd7SJacob Faibussowitsch 
9811f108dbd7SJacob Faibussowitsch   Input Parameters:
9812a1cb98faSBarry Smith + dm   - The `DMPLEX` object
9813a1cb98faSBarry Smith . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
9814f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
9815f108dbd7SJacob Faibussowitsch 
9816f108dbd7SJacob Faibussowitsch   Output Parameters:
981720f4b53cSBarry Smith + OrthQual      - `Vec` containing orthogonal quality per cell
9818a1cb98faSBarry Smith - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
9819f108dbd7SJacob Faibussowitsch 
9820f108dbd7SJacob Faibussowitsch   Options Database Keys:
9821a1cb98faSBarry Smith + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
9822f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view   - view OrthQual vector.
9823f108dbd7SJacob Faibussowitsch 
9824a1cb98faSBarry Smith   Level: intermediate
9825a1cb98faSBarry Smith 
9826f108dbd7SJacob Faibussowitsch   Notes:
9827a4e35b19SJacob Faibussowitsch   Orthogonal quality is given by the following formula\:
9828f108dbd7SJacob Faibussowitsch 
9829a1cb98faSBarry Smith   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
9830f108dbd7SJacob Faibussowitsch 
9831f108dbd7SJacob 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
9832f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
9833f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
9834f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
9835f108dbd7SJacob Faibussowitsch 
9836f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
9837f108dbd7SJacob Faibussowitsch 
9838a1cb98faSBarry Smith   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
9839f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
9840f108dbd7SJacob Faibussowitsch 
9841f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
9842f108dbd7SJacob Faibussowitsch 
98431cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
9844f108dbd7SJacob Faibussowitsch @*/
9845d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
9846d71ae5a4SJacob Faibussowitsch {
98476ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
98486ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
98496ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
9850f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
98516ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
9852f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
9853f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
9854f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
9855f108dbd7SJacob Faibussowitsch   IS                     glob;
9856f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
9857f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
9858f108dbd7SJacob Faibussowitsch 
9859f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
9860f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9861ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
98624f572ea9SToby Isaac   PetscAssertPointer(OrthQual, 4);
98636bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
98649566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
98659566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
986663a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
98676ed19f2fSJacob Faibussowitsch   {
98686ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
98696ed19f2fSJacob Faibussowitsch 
98709566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
9871f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
9872f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
9873f108dbd7SJacob Faibussowitsch 
98749566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
987598921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
9876f108dbd7SJacob Faibussowitsch     }
98776ed19f2fSJacob Faibussowitsch   }
9878f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
98794f572ea9SToby Isaac     PetscAssertPointer(OrthQualLabel, 5);
98809566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
98819566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
98829371c9d4SSatish Balay   } else {
98839371c9d4SSatish Balay     *OrthQualLabel = NULL;
98849371c9d4SSatish Balay   }
98859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
98869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9887e2b8d0fcSMatthew G. Knepley   PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob));
98889566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
98899566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
98909566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
98919566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
98929566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
98939566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
98949566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
98959566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
98969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
98979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
98989566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
98999566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
99009566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
99019566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
99029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
99036ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
99046ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9905f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
9906f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
9907898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
9908f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
9909f108dbd7SJacob Faibussowitsch 
99106ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
9911f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
9912f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
99139566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
99149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9915f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
99169566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
99176ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
99186ed19f2fSJacob Faibussowitsch       PetscInt         i;
99196ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
9920f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9921f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
9922f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
9923f108dbd7SJacob Faibussowitsch 
9924f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9925f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
99269566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9927f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
99286ed19f2fSJacob Faibussowitsch       {
99296ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
99306ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
99316ed19f2fSJacob Faibussowitsch 
99329566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
99339566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
99349566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
99356ed19f2fSJacob Faibussowitsch       }
9936f108dbd7SJacob Faibussowitsch 
9937f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9938f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9939f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9940f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9941f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9942addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9943addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9944addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9945f108dbd7SJacob Faibussowitsch       }
9946addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9947addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9948addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9949f108dbd7SJacob Faibussowitsch 
9950f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9951f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9952f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
9953f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
9954f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
9955f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9956f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
9957f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
9958f108dbd7SJacob Faibussowitsch       }
9959ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
9960ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
9961f108dbd7SJacob Faibussowitsch     }
99629566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
99639566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9964f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
99656ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9966f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
99679566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9968f108dbd7SJacob Faibussowitsch     }
9969f108dbd7SJacob Faibussowitsch   }
99709566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
99719566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
99729566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
99739566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
99749566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
9975648c30bcSBarry Smith   PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9976f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
99779566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9978f108dbd7SJacob Faibussowitsch   }
99799566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
9980648c30bcSBarry Smith   PetscCall(PetscViewerDestroy(&vwr));
99819566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
99823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9983f108dbd7SJacob Faibussowitsch }
9984f108dbd7SJacob Faibussowitsch 
9985d5b43468SJose E. Roman /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
99861eb70e55SToby Isaac  * interpolator construction */
9987d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9988d71ae5a4SJacob Faibussowitsch {
99891eb70e55SToby Isaac   PetscSection section, newSection, gsection;
99901eb70e55SToby Isaac   PetscSF      sf;
99911eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
99921eb70e55SToby Isaac 
99931eb70e55SToby Isaac   PetscFunctionBegin;
99941eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
99954f572ea9SToby Isaac   PetscAssertPointer(odm, 2);
99969566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
99979566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
9998712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
99991eb70e55SToby Isaac   if (!ghasConstraints) {
100009566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
100011eb70e55SToby Isaac     *odm = dm;
100023ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
100031eb70e55SToby Isaac   }
100049566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
10005bb4b53efSMatthew G. Knepley   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm));
100069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
100079566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
10008eb9d3e4dSMatthew G. Knepley   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection));
100099566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
100109566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
100113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100121eb70e55SToby Isaac }
100131eb70e55SToby Isaac 
10014d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
10015d71ae5a4SJacob Faibussowitsch {
100161eb70e55SToby Isaac   DM        dmco, dmfo;
100171eb70e55SToby Isaac   Mat       interpo;
100181eb70e55SToby Isaac   Vec       rscale;
100191eb70e55SToby Isaac   Vec       cglobalo, clocal;
100201eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
100211eb70e55SToby Isaac   PetscBool regular;
100221eb70e55SToby Isaac 
100231eb70e55SToby Isaac   PetscFunctionBegin;
100249566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
100259566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
100269566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
100279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
100289566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
100299566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
100309566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
100319566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
100329566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
100339566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
100349566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
100359566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
100369566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
100379566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
100389566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
100399566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
100409566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
100419566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
100429566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
100439566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
100449566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
100459566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
100469566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
100479566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
100481eb70e55SToby Isaac   *shift = fglobal;
100499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
100509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
100519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
100529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
100539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
100549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
100559566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
100569566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
100573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100581eb70e55SToby Isaac }
100591eb70e55SToby Isaac 
10060d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
10061d71ae5a4SJacob Faibussowitsch {
100621eb70e55SToby Isaac   PetscObject shifto;
100631eb70e55SToby Isaac   Vec         shift;
100641eb70e55SToby Isaac 
100651eb70e55SToby Isaac   PetscFunctionBegin;
100661eb70e55SToby Isaac   if (!interp) {
100671eb70e55SToby Isaac     Vec rscale;
100681eb70e55SToby Isaac 
100699566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
100709566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
100711eb70e55SToby Isaac   } else {
100729566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
100731eb70e55SToby Isaac   }
100749566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
100751eb70e55SToby Isaac   if (!shifto) {
100769566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
100779566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
100781eb70e55SToby Isaac     shifto = (PetscObject)shift;
100799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
100801eb70e55SToby Isaac   }
100811eb70e55SToby Isaac   shift = (Vec)shifto;
100829566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
100839566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
100849566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
100853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100861eb70e55SToby Isaac }
100871eb70e55SToby Isaac 
10088bceba477SMatthew G. Knepley /* Pointwise interpolation
10089bceba477SMatthew G. Knepley      Just code FEM for now
10090bceba477SMatthew G. Knepley      u^f = I u^c
100914ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
100924ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
100934ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
10094bceba477SMatthew G. Knepley */
10095d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
10096d71ae5a4SJacob Faibussowitsch {
10097bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
10098bceba477SMatthew G. Knepley   PetscInt     m, n;
10099a063dac3SMatthew G. Knepley   void        *ctx;
1010068132eb9SMatthew G. Knepley   DM           cdm;
10101cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
10102bceba477SMatthew G. Knepley 
10103bceba477SMatthew G. Knepley   PetscFunctionBegin;
101049566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
101059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
101069566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
101079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
1010868132eb9SMatthew G. Knepley 
101099566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
101109566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
101119566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
101129566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
101139566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
1011468132eb9SMatthew G. Knepley 
101159566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
101169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
101179566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
101189566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
101199566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
101204db47ee9SStefano Zampini   if (scaling) {
101215d1c2e58SMatthew G. Knepley     /* Use naive scaling */
101229566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
101234db47ee9SStefano Zampini   }
101243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10125a063dac3SMatthew G. Knepley }
10126bceba477SMatthew G. Knepley 
10127d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
10128d71ae5a4SJacob Faibussowitsch {
101296dbf9973SLawrence Mitchell   VecScatter ctx;
1013090748bafSMatthew G. Knepley 
10131a063dac3SMatthew G. Knepley   PetscFunctionBegin;
101329566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
101339566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
101349566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
101353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10136bceba477SMatthew G. Knepley }
10137bceba477SMatthew G. Knepley 
10138d71ae5a4SJacob 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[])
10139d71ae5a4SJacob Faibussowitsch {
10140a102dd69SStefano Zampini   const PetscInt f  = (PetscInt)PetscRealPart(constants[numConstants]);
10141a102dd69SStefano Zampini   const PetscInt Nc = uOff[f + 1] - uOff[f];
10142a102dd69SStefano Zampini   for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
101433e9753d6SMatthew G. Knepley }
101443e9753d6SMatthew G. Knepley 
101458e9849d2SStefano Zampini PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass)
10146d71ae5a4SJacob Faibussowitsch {
10147b4937a87SMatthew G. Knepley   DM           dmc;
10148b4937a87SMatthew G. Knepley   PetscDS      ds;
10149b4937a87SMatthew G. Knepley   Vec          ones, locmass;
10150b4937a87SMatthew G. Knepley   IS           cellIS;
10151b4937a87SMatthew G. Knepley   PetscFormKey key;
10152b4937a87SMatthew G. Knepley   PetscInt     depth;
10153b4937a87SMatthew G. Knepley 
10154b4937a87SMatthew G. Knepley   PetscFunctionBegin;
101559566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
101569566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
101579566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
10158a102dd69SStefano Zampini   for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
101598e9849d2SStefano Zampini   if (mass) PetscCall(DMCreateGlobalVector(dm, mass));
101608e9849d2SStefano Zampini   if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass));
101618e9849d2SStefano Zampini   else PetscCall(DMGetLocalVector(dm, &locmass));
101628e9849d2SStefano Zampini   PetscCall(DMGetLocalVector(dm, &ones));
101638e9849d2SStefano Zampini   PetscCall(DMPlexGetDepth(dm, &depth));
101648e9849d2SStefano Zampini   PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS));
101659566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
101669566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
10167b4937a87SMatthew G. Knepley   key.label = NULL;
10168b4937a87SMatthew G. Knepley   key.value = 0;
10169b4937a87SMatthew G. Knepley   key.field = 0;
10170b4937a87SMatthew G. Knepley   key.part  = 0;
101719566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
101729566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
101738e9849d2SStefano Zampini   if (mass) {
101748e9849d2SStefano Zampini     PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass));
101758e9849d2SStefano Zampini     PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass));
101768e9849d2SStefano Zampini   }
101778e9849d2SStefano Zampini   PetscCall(DMRestoreLocalVector(dm, &ones));
101788e9849d2SStefano Zampini   if (lmass) *lmass = locmass;
101798e9849d2SStefano Zampini   else PetscCall(DMRestoreLocalVector(dm, &locmass));
101809566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
101813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10182b4937a87SMatthew G. Knepley }
10183b4937a87SMatthew G. Knepley 
10184d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
10185d71ae5a4SJacob Faibussowitsch {
10186bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
10187bd041c0cSMatthew G. Knepley   PetscInt     m, n;
10188bd041c0cSMatthew G. Knepley   void        *ctx;
10189bd041c0cSMatthew G. Knepley   DM           cdm;
10190bd041c0cSMatthew G. Knepley   PetscBool    regular;
10191bd041c0cSMatthew G. Knepley 
10192bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
101933e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
101943e9753d6SMatthew G. Knepley     DM            dmc;
101953e9753d6SMatthew G. Knepley     PetscDS       ds;
10196b4937a87SMatthew G. Knepley     PetscWeakForm wf;
101973e9753d6SMatthew G. Knepley     Vec           u;
101983e9753d6SMatthew G. Knepley     IS            cellIS;
1019906ad1575SMatthew G. Knepley     PetscFormKey  key;
102003e9753d6SMatthew G. Knepley     PetscInt      depth;
102013e9753d6SMatthew G. Knepley 
102029566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
102039566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
102049566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
102059566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
102069566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
10207a102dd69SStefano Zampini     for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL));
102089566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
102098d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
102109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
102119566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
102129566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
102136528b96dSMatthew G. Knepley     key.label = NULL;
102146528b96dSMatthew G. Knepley     key.value = 0;
102156528b96dSMatthew G. Knepley     key.field = 0;
1021606ad1575SMatthew G. Knepley     key.part  = 0;
102179566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
102189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
102198d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
102209566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
102213e9753d6SMatthew G. Knepley   } else {
102229566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
102239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
102249566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
102259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10226bd041c0cSMatthew G. Knepley 
102279566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
102289566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
102299566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
102309566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
10231bd041c0cSMatthew G. Knepley 
102329566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
102339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
102349566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
102359566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
102363e9753d6SMatthew G. Knepley   }
102379566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
102383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10239bd041c0cSMatthew G. Knepley }
10240bd041c0cSMatthew G. Knepley 
102410aef6b92SMatthew G. Knepley /*@
102420aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
102430aef6b92SMatthew G. Knepley 
102440aef6b92SMatthew G. Knepley   Input Parameter:
10245a1cb98faSBarry Smith . dm - The `DMPLEX` object
102460aef6b92SMatthew G. Knepley 
102470aef6b92SMatthew G. Knepley   Output Parameter:
102480aef6b92SMatthew G. Knepley . regular - The flag
102490aef6b92SMatthew G. Knepley 
102500aef6b92SMatthew G. Knepley   Level: intermediate
102510aef6b92SMatthew G. Knepley 
102521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
102530aef6b92SMatthew G. Knepley @*/
10254d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
10255d71ae5a4SJacob Faibussowitsch {
102560aef6b92SMatthew G. Knepley   PetscFunctionBegin;
102570aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102584f572ea9SToby Isaac   PetscAssertPointer(regular, 2);
102590aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
102603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102610aef6b92SMatthew G. Knepley }
102620aef6b92SMatthew G. Knepley 
102630aef6b92SMatthew G. Knepley /*@
102640aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
102650aef6b92SMatthew G. Knepley 
102660aef6b92SMatthew G. Knepley   Input Parameters:
10267a1cb98faSBarry Smith + dm      - The `DMPLEX` object
102680aef6b92SMatthew G. Knepley - regular - The flag
102690aef6b92SMatthew G. Knepley 
102700aef6b92SMatthew G. Knepley   Level: intermediate
102710aef6b92SMatthew G. Knepley 
102721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
102730aef6b92SMatthew G. Knepley @*/
10274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
10275d71ae5a4SJacob Faibussowitsch {
102760aef6b92SMatthew G. Knepley   PetscFunctionBegin;
102770aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102780aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
102793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102800aef6b92SMatthew G. Knepley }
102810aef6b92SMatthew G. Knepley 
10282a68b90caSToby Isaac /*@
10283f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
10284a1cb98faSBarry Smith   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
10285a68b90caSToby Isaac 
10286a1cb98faSBarry Smith   Not Collective
10287a68b90caSToby Isaac 
10288f899ff85SJose E. Roman   Input Parameter:
10289a1cb98faSBarry Smith . dm - The `DMPLEX` object
10290a68b90caSToby Isaac 
10291a68b90caSToby Isaac   Output Parameters:
1029220f4b53cSBarry Smith + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
1029320f4b53cSBarry Smith - anchorIS      - If not `NULL`, set to the list of anchors indexed by `anchorSection`
10294a68b90caSToby Isaac 
10295a68b90caSToby Isaac   Level: intermediate
10296a68b90caSToby Isaac 
102971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
10298a68b90caSToby Isaac @*/
10299d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
10300d71ae5a4SJacob Faibussowitsch {
10301a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
10302a68b90caSToby Isaac 
10303a68b90caSToby Isaac   PetscFunctionBegin;
10304a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
103059566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
10306a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
10307a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
103083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10309a68b90caSToby Isaac }
10310a68b90caSToby Isaac 
10311a68b90caSToby Isaac /*@
10312a4e35b19SJacob Faibussowitsch   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.
10313a68b90caSToby Isaac 
1031420f4b53cSBarry Smith   Collective
10315a68b90caSToby Isaac 
10316a68b90caSToby Isaac   Input Parameters:
10317a1cb98faSBarry Smith + dm            - The `DMPLEX` object
10318a1cb98faSBarry Smith . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
10319a1cb98faSBarry Smith                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10320a1cb98faSBarry Smith - anchorIS      - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10321a68b90caSToby Isaac 
10322a68b90caSToby Isaac   Level: intermediate
10323a68b90caSToby Isaac 
10324a1cb98faSBarry Smith   Notes:
10325a4e35b19SJacob Faibussowitsch   Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to
10326a4e35b19SJacob Faibussowitsch   an outside value, the anchor constraints set a point's degrees of freedom to be a linear
10327a4e35b19SJacob Faibussowitsch   combination of other points' degrees of freedom.
10328a4e35b19SJacob Faibussowitsch 
10329a1cb98faSBarry Smith   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
10330a1cb98faSBarry Smith   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
10331a1cb98faSBarry Smith 
1033220f4b53cSBarry Smith   The reference counts of `anchorSection` and `anchorIS` are incremented.
10333a1cb98faSBarry Smith 
103341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
10335a68b90caSToby Isaac @*/
10336d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
10337d71ae5a4SJacob Faibussowitsch {
10338a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
10339e228b242SToby Isaac   PetscMPIInt result;
10340a68b90caSToby Isaac 
10341a68b90caSToby Isaac   PetscFunctionBegin;
10342a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10343e228b242SToby Isaac   if (anchorSection) {
10344e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
103459566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
103461dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
10347e228b242SToby Isaac   }
10348e228b242SToby Isaac   if (anchorIS) {
10349e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
103509566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
103511dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
10352e228b242SToby Isaac   }
10353a68b90caSToby Isaac 
103549566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
103559566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
10356a68b90caSToby Isaac   plex->anchorSection = anchorSection;
10357a68b90caSToby Isaac 
103589566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
103599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
10360a68b90caSToby Isaac   plex->anchorIS = anchorIS;
10361a68b90caSToby Isaac 
10362cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
10363a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
10364a68b90caSToby Isaac     const PetscInt *anchors;
10365a68b90caSToby Isaac 
103669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
103679566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
103689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
10369a68b90caSToby Isaac     for (a = 0; a < size; a++) {
10370a68b90caSToby Isaac       PetscInt p;
10371a68b90caSToby Isaac 
10372a68b90caSToby Isaac       p = anchors[a];
10373a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
10374a68b90caSToby Isaac         PetscInt dof;
10375a68b90caSToby Isaac 
103769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10377a68b90caSToby Isaac         if (dof) {
103789566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
1037963a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
10380a68b90caSToby Isaac         }
10381a68b90caSToby Isaac       }
10382a68b90caSToby Isaac     }
103839566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
10384a68b90caSToby Isaac   }
10385f7c74593SToby Isaac   /* reset the generic constraints */
103869566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
103873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10388a68b90caSToby Isaac }
10389a68b90caSToby Isaac 
10390d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
10391d71ae5a4SJacob Faibussowitsch {
10392f7c74593SToby Isaac   PetscSection anchorSection;
103936995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
10394a68b90caSToby Isaac 
10395a68b90caSToby Isaac   PetscFunctionBegin;
10396a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
103979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
103989566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
103999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
104006995de1eSToby Isaac   if (numFields) {
10401719ab38cSToby Isaac     PetscInt f;
104029566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
10403719ab38cSToby Isaac 
10404719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
10405719ab38cSToby Isaac       PetscInt numComp;
10406719ab38cSToby Isaac 
104079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
104089566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
10409719ab38cSToby Isaac     }
104106995de1eSToby Isaac   }
104119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
104129566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
104136995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
104146995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
104156995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
104169566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
10417a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
104189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10419a68b90caSToby Isaac     if (dof) {
104209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
104219566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
10422a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
104239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
104249566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
10425a68b90caSToby Isaac       }
10426a68b90caSToby Isaac     }
10427a68b90caSToby Isaac   }
104289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
104299566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
104303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10431a68b90caSToby Isaac }
10432a68b90caSToby Isaac 
10433d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
10434d71ae5a4SJacob Faibussowitsch {
10435f7c74593SToby Isaac   PetscSection    aSec;
10436ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
104370ac89760SToby Isaac   const PetscInt *anchors;
104380ac89760SToby Isaac   PetscInt        numFields, f;
1043966ad2231SToby Isaac   IS              aIS;
10440e19f7ee6SMark Adams   MatType         mtype;
10441e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
104420ac89760SToby Isaac 
104430ac89760SToby Isaac   PetscFunctionBegin;
104440ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
104459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
104469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
104479566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
104489566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
104499566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
104509566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
104519566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
104529566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
10453e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
10454e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
10455e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
104569566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
104579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
104589566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
104596995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
104609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
104619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
104629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
104630ac89760SToby Isaac   i[0] = 0;
104649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
104650ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
10466f19733c5SToby Isaac     PetscInt rDof, rOff, r;
10467f19733c5SToby Isaac 
104689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10469f19733c5SToby Isaac     if (!rDof) continue;
104709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
104710ac89760SToby Isaac     if (numFields) {
104720ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
104730ac89760SToby Isaac         annz = 0;
10474f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
10475f19733c5SToby Isaac           a = anchors[rOff + r];
10476ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
104779566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
104780ac89760SToby Isaac           annz += aDof;
104790ac89760SToby Isaac         }
104809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
104819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10482ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
104830ac89760SToby Isaac       }
104842f7452b8SBarry Smith     } else {
104850ac89760SToby Isaac       annz = 0;
104869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
104870ac89760SToby Isaac       for (q = 0; q < dof; q++) {
10488ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
10489ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
104909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
104910ac89760SToby Isaac         annz += aDof;
104920ac89760SToby Isaac       }
104939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
104949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10495ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
104960ac89760SToby Isaac     }
104970ac89760SToby Isaac   }
104980ac89760SToby Isaac   nnz = i[m];
104999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
105000ac89760SToby Isaac   offset = 0;
105010ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
105020ac89760SToby Isaac     if (numFields) {
105030ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
105049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
105050ac89760SToby Isaac         for (q = 0; q < dof; q++) {
105060ac89760SToby Isaac           PetscInt rDof, rOff, r;
105079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
105089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
105090ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
105100ac89760SToby Isaac             PetscInt s;
105110ac89760SToby Isaac 
105120ac89760SToby Isaac             a = anchors[rOff + r];
10513ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
105149566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
105159566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10516ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
105170ac89760SToby Isaac           }
105180ac89760SToby Isaac         }
105190ac89760SToby Isaac       }
105202f7452b8SBarry Smith     } else {
105219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
105220ac89760SToby Isaac       for (q = 0; q < dof; q++) {
105230ac89760SToby Isaac         PetscInt rDof, rOff, r;
105249566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
105259566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
105260ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
105270ac89760SToby Isaac           PetscInt s;
105280ac89760SToby Isaac 
105290ac89760SToby Isaac           a = anchors[rOff + r];
10530ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
105319566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
105329566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10533ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
105340ac89760SToby Isaac         }
105350ac89760SToby Isaac       }
105360ac89760SToby Isaac     }
105370ac89760SToby Isaac   }
105389566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
105399566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
105409566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
105419566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
105423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105430ac89760SToby Isaac }
105440ac89760SToby Isaac 
10545d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10546d71ae5a4SJacob Faibussowitsch {
10547f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
10548f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
1054966ad2231SToby Isaac   Mat          cMat;
1055066ad2231SToby Isaac 
1055166ad2231SToby Isaac   PetscFunctionBegin;
1055266ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
105539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
1055466ad2231SToby Isaac   if (anchorSection) {
1055544a7f3ddSMatthew G. Knepley     PetscInt Nf;
10556e228b242SToby Isaac 
105579566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
105589566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
105599566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
105609566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
105619566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
105629566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
105639566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
105649566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
1056566ad2231SToby Isaac   }
105663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1056766ad2231SToby Isaac }
10568a93c429eSMatthew G. Knepley 
10569d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10570d71ae5a4SJacob Faibussowitsch {
10571a93c429eSMatthew G. Knepley   IS           subis;
10572a93c429eSMatthew G. Knepley   PetscSection section, subsection;
10573a93c429eSMatthew G. Knepley 
10574a93c429eSMatthew G. Knepley   PetscFunctionBegin;
105759566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1057628b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
1057728b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10578a93c429eSMatthew G. Knepley   /* Create subdomain */
1057930cbcd5dSksagiyam   PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm));
10580a93c429eSMatthew G. Knepley   /* Create submodel */
105819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
105829566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
105839566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
105849566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
105859566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
10586a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
10587a93c429eSMatthew G. Knepley   if (is) {
10588a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
10589a93c429eSMatthew G. Knepley     IS              spIS;
10590a93c429eSMatthew G. Knepley     const PetscInt *spmap;
10591a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
10592a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10593a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10594a93c429eSMatthew G. Knepley 
105959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
105969566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
105979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
105989566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
105999566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
106009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10601a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10602a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10603a93c429eSMatthew G. Knepley 
106049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10605a93c429eSMatthew G. Knepley       if (gdof > 0) {
10606a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10607a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10608a93c429eSMatthew G. Knepley 
106099566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
106109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10611a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10612a93c429eSMatthew G. Knepley         }
10613a93c429eSMatthew G. Knepley         subSize += pSubSize;
10614a93c429eSMatthew G. Knepley         if (pSubSize) {
10615a93c429eSMatthew G. Knepley           if (bs < 0) {
10616a93c429eSMatthew G. Knepley             bs = pSubSize;
10617a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10618a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10619a93c429eSMatthew G. Knepley             bs = 1;
10620a93c429eSMatthew G. Knepley           }
10621a93c429eSMatthew G. Knepley         }
10622a93c429eSMatthew G. Knepley       }
10623a93c429eSMatthew G. Knepley     }
10624a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
106259371c9d4SSatish Balay     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
106269371c9d4SSatish Balay     bsLocal[1] = bs;
106279566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
106289371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
106299371c9d4SSatish Balay       bs = 1;
106309371c9d4SSatish Balay     } else {
106319371c9d4SSatish Balay       bs = bsMinMax[0];
106329371c9d4SSatish Balay     }
106339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10634a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10635a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10636a93c429eSMatthew G. Knepley 
106379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10638a93c429eSMatthew G. Knepley       if (gdof > 0) {
10639a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10640a93c429eSMatthew G. Knepley 
106419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10642a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10643a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10644a93c429eSMatthew G. Knepley 
10645a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10646a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
106479566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
106489566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10649a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10650a93c429eSMatthew G. Knepley           }
106519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
106529566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10653ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10654a93c429eSMatthew G. Knepley         }
10655a93c429eSMatthew G. Knepley       }
10656a93c429eSMatthew G. Knepley     }
106579566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
106589566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10659a93c429eSMatthew G. Knepley     if (bs > 1) {
10660a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10661a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10662a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10663a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
106649371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
106659371c9d4SSatish Balay             set = 0;
106669371c9d4SSatish Balay             break;
106679371c9d4SSatish Balay           }
10668a93c429eSMatthew G. Knepley         }
10669a93c429eSMatthew G. Knepley       }
106709566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10671a93c429eSMatthew G. Knepley     }
10672a93c429eSMatthew G. Knepley     /* Attach nullspace */
10673a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
10674a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10675a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
10676a93c429eSMatthew G. Knepley     }
10677a93c429eSMatthew G. Knepley     if (f < Nf) {
10678a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
106799566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
106806823f3c5SBlaise Bourdin 
106819566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
106829566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
10683a93c429eSMatthew G. Knepley     }
10684a93c429eSMatthew G. Knepley   }
106853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10686a93c429eSMatthew G. Knepley }
10687c0f0dcc3SMatthew G. Knepley 
10688c0f0dcc3SMatthew G. Knepley /*@
10689c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10690c0f0dcc3SMatthew G. Knepley 
10691a1cb98faSBarry Smith   Input Parameters:
10692a1cb98faSBarry Smith + dm    - The `DM`
10693a1cb98faSBarry Smith - dummy - unused argument
10694a1cb98faSBarry Smith 
10695a1cb98faSBarry Smith   Options Database Key:
10696a1cb98faSBarry Smith . -dm_plex_monitor_throughput - Activate the monitor
10697c0f0dcc3SMatthew G. Knepley 
10698c0f0dcc3SMatthew G. Knepley   Level: developer
10699c0f0dcc3SMatthew G. Knepley 
107001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10701c0f0dcc3SMatthew G. Knepley @*/
10702d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
10703d71ae5a4SJacob Faibussowitsch {
10704b665b14eSToby Isaac   PetscLogHandler default_handler;
10705b665b14eSToby Isaac 
107062611ad71SToby Isaac   PetscFunctionBegin;
107072611ad71SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10708b665b14eSToby Isaac   PetscCall(PetscLogGetDefaultHandler(&default_handler));
10709b665b14eSToby Isaac   if (default_handler) {
10710c0f0dcc3SMatthew G. Knepley     PetscLogEvent      event;
10711c0f0dcc3SMatthew G. Knepley     PetscEventPerfInfo eventInfo;
10712c0f0dcc3SMatthew G. Knepley     PetscReal          cellRate, flopRate;
10713c0f0dcc3SMatthew G. Knepley     PetscInt           cStart, cEnd, Nf, N;
10714c0f0dcc3SMatthew G. Knepley     const char        *name;
10715c0f0dcc3SMatthew G. Knepley 
107169566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
107179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
107189566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
107199566063dSJacob Faibussowitsch     PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
10720b665b14eSToby Isaac     PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo));
10721c0f0dcc3SMatthew G. Knepley     N        = (cEnd - cStart) * Nf * eventInfo.count;
10722c0f0dcc3SMatthew G. Knepley     flopRate = eventInfo.flops / eventInfo.time;
10723c0f0dcc3SMatthew G. Knepley     cellRate = N / eventInfo.time;
1072463a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " integrals %d reps\n  Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double)cellRate, (double)(flopRate / 1.e6)));
107252611ad71SToby Isaac   } else {
10726b665b14eSToby 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.");
107272611ad71SToby Isaac   }
107283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10729c0f0dcc3SMatthew G. Knepley }
10730