xref: /petsc/src/dm/impls/plex/plex.c (revision bd3611e6935c004c6a31a13edc0a8a9049c5b495)
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>
11552f7358SJed Brown 
12552f7358SJed Brown /* Logging support */
1302f7d72cSksagiyam 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;
14172ee266SJed Brown PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;
15552f7358SJed Brown 
16f39ec787SMatthew G. Knepley PetscBool  Plexcite       = PETSC_FALSE;
17f39ec787SMatthew G. Knepley const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n"
18f39ec787SMatthew G. Knepley                             "title     = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n"
19f39ec787SMatthew G. Knepley                             "author    = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n"
20f39ec787SMatthew G. Knepley                             "journal   = {SIAM Journal on Scientific Computing},\n"
21f39ec787SMatthew G. Knepley                             "volume    = {38},\n"
22f39ec787SMatthew G. Knepley                             "number    = {5},\n"
23f39ec787SMatthew G. Knepley                             "pages     = {S143--S155},\n"
24f39ec787SMatthew G. Knepley                             "eprint    = {http://arxiv.org/abs/1506.07749},\n"
25f39ec787SMatthew G. Knepley                             "doi       = {10.1137/15M1026092},\n"
26f39ec787SMatthew G. Knepley                             "year      = {2016},\n"
27f39ec787SMatthew G. Knepley                             "petsc_uses={DMPlex},\n}\n";
28f39ec787SMatthew G. Knepley 
295a576424SJed Brown PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
30552f7358SJed Brown 
31e5337592SStefano Zampini /*@
329318fe57SMatthew G. Knepley   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
339318fe57SMatthew G. Knepley 
349318fe57SMatthew G. Knepley   Input Parameter:
35a1cb98faSBarry Smith . dm - The `DMPLEX` object
369318fe57SMatthew G. Knepley 
379318fe57SMatthew G. Knepley   Output Parameter:
389318fe57SMatthew G. Knepley . simplex - Flag checking for a simplex
399318fe57SMatthew G. Knepley 
409318fe57SMatthew G. Knepley   Level: intermediate
419318fe57SMatthew G. Knepley 
42a1cb98faSBarry Smith   Note:
43a1cb98faSBarry Smith   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
44a1cb98faSBarry Smith   If the mesh has no cells, this returns `PETSC_FALSE`.
45a1cb98faSBarry Smith 
461cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
479318fe57SMatthew G. Knepley @*/
48d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
49d71ae5a4SJacob Faibussowitsch {
509318fe57SMatthew G. Knepley   DMPolytopeType ct;
519318fe57SMatthew G. Knepley   PetscInt       cStart, cEnd;
529318fe57SMatthew G. Knepley 
539318fe57SMatthew G. Knepley   PetscFunctionBegin;
549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
559371c9d4SSatish Balay   if (cEnd <= cStart) {
569371c9d4SSatish Balay     *simplex = PETSC_FALSE;
573ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
589371c9d4SSatish Balay   }
599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
609318fe57SMatthew G. Knepley   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
629318fe57SMatthew G. Knepley }
639318fe57SMatthew G. Knepley 
649318fe57SMatthew G. Knepley /*@
65412e9a14SMatthew G. Knepley   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
66e5337592SStefano Zampini 
67d8d19677SJose E. Roman   Input Parameters:
68a1cb98faSBarry Smith + dm     - The `DMPLEX` object
69412e9a14SMatthew G. Knepley - height - The cell height in the Plex, 0 is the default
70e5337592SStefano Zampini 
71e5337592SStefano Zampini   Output Parameters:
72412e9a14SMatthew G. Knepley + cStart - The first "normal" cell
7340196513SBarry Smith - cEnd   - The upper bound on "normal" cells
74e5337592SStefano Zampini 
75412e9a14SMatthew G. Knepley   Level: developer
76e5337592SStefano Zampini 
77a1cb98faSBarry Smith   Note:
785ae96e2bSMatthew G. Knepley   This function requires that tensor cells are ordered last.
79a1cb98faSBarry Smith 
802827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
81e5337592SStefano Zampini @*/
82d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
83d71ae5a4SJacob Faibussowitsch {
845ae96e2bSMatthew G. Knepley   DMLabel         ctLabel;
855ae96e2bSMatthew G. Knepley   IS              valueIS;
865ae96e2bSMatthew G. Knepley   const PetscInt *ctypes;
875ae96e2bSMatthew G. Knepley   PetscInt        Nct, cS = PETSC_MAX_INT, cE = 0;
88e5337592SStefano Zampini 
89e5337592SStefano Zampini   PetscFunctionBegin;
909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
915ae96e2bSMatthew G. Knepley   PetscCall(DMLabelGetValueIS(ctLabel, &valueIS));
925ae96e2bSMatthew G. Knepley   PetscCall(ISGetLocalSize(valueIS, &Nct));
935ae96e2bSMatthew G. Knepley   PetscCall(ISGetIndices(valueIS, &ctypes));
945ae96e2bSMatthew G. Knepley   if (!Nct) cS = cE = 0;
955ae96e2bSMatthew G. Knepley   for (PetscInt t = 0; t < Nct; ++t) {
96c306944fSJed Brown     const DMPolytopeType ct = (DMPolytopeType)ctypes[t];
975ae96e2bSMatthew G. Knepley     PetscInt             ctS, ctE, ht;
985ae96e2bSMatthew G. Knepley 
995ae96e2bSMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) {
1005ae96e2bSMatthew G. Knepley       // If any cells are not typed, just use all cells
1015ae96e2bSMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd));
1025ae96e2bSMatthew G. Knepley       break;
1035ae96e2bSMatthew G. Knepley     }
104c306944fSJed Brown     if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue;
1055ae96e2bSMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE));
1065ae96e2bSMatthew G. Knepley     if (ctS >= ctE) continue;
1075ae96e2bSMatthew G. Knepley     // Check that a point has the right height
1085ae96e2bSMatthew G. Knepley     PetscCall(DMPlexGetPointHeight(dm, ctS, &ht));
1095ae96e2bSMatthew G. Knepley     if (ht != height) continue;
1105ae96e2bSMatthew G. Knepley     cS = PetscMin(cS, ctS);
1115ae96e2bSMatthew G. Knepley     cE = PetscMax(cE, ctE);
1125ae96e2bSMatthew G. Knepley   }
1135ae96e2bSMatthew G. Knepley   PetscCall(ISDestroy(&valueIS));
114695799ffSMatthew G. Knepley   // Reset label for fast lookup
115695799ffSMatthew G. Knepley   PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
116412e9a14SMatthew G. Knepley   if (cStart) *cStart = cS;
117412e9a14SMatthew G. Knepley   if (cEnd) *cEnd = cE;
1183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
119e5337592SStefano Zampini }
120e5337592SStefano Zampini 
1219c600e38SMatt McGurn PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft)
1229c600e38SMatt McGurn {
1239c600e38SMatt McGurn   PetscInt                 cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t;
1249c600e38SMatt McGurn   PetscInt                *sStart, *sEnd;
1259c600e38SMatt McGurn   PetscViewerVTKFieldType *ft;
1269c600e38SMatt McGurn   PetscInt                 vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1];
1279c600e38SMatt McGurn   DMLabel                  depthLabel, ctLabel;
1289c600e38SMatt McGurn 
1299c600e38SMatt McGurn   PetscFunctionBegin;
1309c600e38SMatt McGurn 
1319c600e38SMatt McGurn   /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */
1329c600e38SMatt McGurn   PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1));
1339c600e38SMatt McGurn   PetscCall(DMGetCoordinateDim(dm, &cdim));
1349c600e38SMatt McGurn   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1359c600e38SMatt McGurn   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1369c600e38SMatt McGurn   if (field >= 0) {
1379c600e38SMatt McGurn     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES]));
1389c600e38SMatt McGurn   } else {
1399c600e38SMatt McGurn     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES]));
1409c600e38SMatt McGurn   }
1419c600e38SMatt McGurn 
1429c600e38SMatt McGurn   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1439c600e38SMatt McGurn   PetscCall(DMPlexGetDepth(dm, &depth));
1449c600e38SMatt McGurn   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
1459c600e38SMatt McGurn   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
1469c600e38SMatt McGurn   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
1479c600e38SMatt McGurn     const DMPolytopeType ict = (DMPolytopeType)c;
1489c600e38SMatt McGurn     PetscInt             dep;
1499c600e38SMatt McGurn 
1509c600e38SMatt McGurn     if (ict == DM_POLYTOPE_FV_GHOST) continue;
1519c600e38SMatt McGurn     PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
1529c600e38SMatt McGurn     if (pStart >= 0) {
1539c600e38SMatt McGurn       PetscCall(DMLabelGetValue(depthLabel, cStart, &dep));
1549c600e38SMatt McGurn       if (dep != depth - cellHeight) continue;
1559c600e38SMatt McGurn     }
1569c600e38SMatt McGurn     if (field >= 0) {
1579c600e38SMatt McGurn       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c]));
1589c600e38SMatt McGurn     } else {
1599c600e38SMatt McGurn       if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c]));
1609c600e38SMatt McGurn     }
1619c600e38SMatt McGurn     PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1629c600e38SMatt McGurn   }
1639c600e38SMatt McGurn 
1649c600e38SMatt McGurn   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1659c600e38SMatt McGurn   *types = 0;
1669c600e38SMatt McGurn 
1679c600e38SMatt McGurn   for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) {
1689c600e38SMatt McGurn     if (globalvcdof[c]) ++(*types);
1699c600e38SMatt McGurn   }
1709c600e38SMatt McGurn 
1719c600e38SMatt McGurn   PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft));
1729c600e38SMatt McGurn   t = 0;
1739c600e38SMatt McGurn   if (globalvcdof[DM_NUM_POLYTOPES]) {
1749c600e38SMatt McGurn     sStart[t] = vStart;
1759c600e38SMatt McGurn     sEnd[t]   = vEnd;
1769c600e38SMatt McGurn     ft[t]     = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
1779c600e38SMatt McGurn     ++t;
1789c600e38SMatt McGurn   }
1799c600e38SMatt McGurn 
1809c600e38SMatt McGurn   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
1819c600e38SMatt McGurn     if (globalvcdof[c]) {
1829c600e38SMatt McGurn       const DMPolytopeType ict = (DMPolytopeType)c;
1839c600e38SMatt McGurn 
1849c600e38SMatt McGurn       PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd));
1859c600e38SMatt McGurn       sStart[t] = cStart;
1869c600e38SMatt McGurn       sEnd[t]   = cEnd;
1879c600e38SMatt McGurn       ft[t]     = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD;
1889c600e38SMatt McGurn       ++t;
1899c600e38SMatt McGurn     }
1909c600e38SMatt McGurn   }
1919c600e38SMatt McGurn 
1929c600e38SMatt McGurn   if (!(*types)) {
1939c600e38SMatt McGurn     if (field >= 0) {
1949c600e38SMatt McGurn       const char *fieldname;
1959c600e38SMatt McGurn 
1969c600e38SMatt McGurn       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
1979c600e38SMatt McGurn       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
1989c600e38SMatt McGurn     } else {
1999c600e38SMatt McGurn       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
2009c600e38SMatt McGurn     }
2019c600e38SMatt McGurn   }
2029c600e38SMatt McGurn 
2039c600e38SMatt McGurn   *ssStart = sStart;
2049c600e38SMatt McGurn   *ssEnd   = sEnd;
2059c600e38SMatt McGurn   *sft     = ft;
2069c600e38SMatt McGurn   PetscFunctionReturn(PETSC_SUCCESS);
2079c600e38SMatt McGurn }
2089c600e38SMatt McGurn 
2099c600e38SMatt McGurn PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft)
2109c600e38SMatt McGurn {
2119c600e38SMatt McGurn   PetscFunctionBegin;
2129c600e38SMatt McGurn   PetscCall(PetscFree3(*sStart, *sEnd, *ft));
2139c600e38SMatt McGurn   PetscFunctionReturn(PETSC_SUCCESS);
2149c600e38SMatt McGurn }
2159c600e38SMatt McGurn 
216d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
217d71ae5a4SJacob Faibussowitsch {
218412e9a14SMatthew G. Knepley   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
219a99a26bcSAdrian Croucher   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
2207e42fee7SMatthew G. Knepley 
2217e42fee7SMatthew G. Knepley   PetscFunctionBegin;
222e630c359SToby Isaac   *ft = PETSC_VTK_INVALID;
2239566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
2249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
2269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
2277e42fee7SMatthew G. Knepley   if (field >= 0) {
2289566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
2299566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
2307e42fee7SMatthew G. Knepley   } else {
2319566063dSJacob Faibussowitsch     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
2329566063dSJacob Faibussowitsch     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
2337e42fee7SMatthew G. Knepley   }
234712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
235a99a26bcSAdrian Croucher   if (globalvcdof[0]) {
2367e42fee7SMatthew G. Knepley     *sStart = vStart;
2377e42fee7SMatthew G. Knepley     *sEnd   = vEnd;
238f094498dSMatthew G. Knepley     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
2397e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_POINT_FIELD;
240a99a26bcSAdrian Croucher   } else if (globalvcdof[1]) {
2417e42fee7SMatthew G. Knepley     *sStart = cStart;
2427e42fee7SMatthew G. Knepley     *sEnd   = cEnd;
243f094498dSMatthew G. Knepley     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
2447e42fee7SMatthew G. Knepley     else *ft = PETSC_VTK_CELL_FIELD;
245e630c359SToby Isaac   } else {
246e630c359SToby Isaac     if (field >= 0) {
247e630c359SToby Isaac       const char *fieldname;
248e630c359SToby Isaac 
2499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
25063a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
251e630c359SToby Isaac     } else {
25263a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
253e630c359SToby Isaac     }
254e630c359SToby Isaac   }
2553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2567e42fee7SMatthew G. Knepley }
2577e42fee7SMatthew G. Knepley 
2586913077dSMatthew G. Knepley /*@
2596913077dSMatthew G. Knepley   DMPlexVecView1D - Plot many 1D solutions on the same line graph
2606913077dSMatthew G. Knepley 
26120f4b53cSBarry Smith   Collective
2626913077dSMatthew G. Knepley 
2636913077dSMatthew G. Knepley   Input Parameters:
264a1cb98faSBarry Smith + dm     - The `DMPLEX` object
2656913077dSMatthew G. Knepley . n      - The number of vectors
2666913077dSMatthew G. Knepley . u      - The array of local vectors
267a1cb98faSBarry Smith - viewer - The `PetscViewer`
2686913077dSMatthew G. Knepley 
2696913077dSMatthew G. Knepley   Level: advanced
2706913077dSMatthew G. Knepley 
2711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
2726913077dSMatthew G. Knepley @*/
273d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
274d71ae5a4SJacob Faibussowitsch {
2756913077dSMatthew G. Knepley   PetscDS            ds;
2766913077dSMatthew G. Knepley   PetscDraw          draw = NULL;
2776913077dSMatthew G. Knepley   PetscDrawLG        lg;
2786913077dSMatthew G. Knepley   Vec                coordinates;
2796913077dSMatthew G. Knepley   const PetscScalar *coords, **sol;
2806913077dSMatthew G. Knepley   PetscReal         *vals;
2816913077dSMatthew G. Knepley   PetscInt          *Nc;
2826913077dSMatthew G. Knepley   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
2836913077dSMatthew G. Knepley   char             **names;
2846913077dSMatthew G. Knepley 
2856913077dSMatthew G. Knepley   PetscFunctionBegin;
2869566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
2879566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
2889566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
2899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponents(ds, &Nc));
2906913077dSMatthew G. Knepley 
2919566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2923ba16761SJacob Faibussowitsch   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
2939566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
2946913077dSMatthew G. Knepley 
2959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
2966913077dSMatthew G. Knepley   for (i = 0, l = 0; i < n; ++i) {
2976913077dSMatthew G. Knepley     const char *vname;
2986913077dSMatthew G. Knepley 
2999566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
3006913077dSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
3016913077dSMatthew G. Knepley       PetscObject disc;
3026913077dSMatthew G. Knepley       const char *fname;
3036913077dSMatthew G. Knepley       char        tmpname[PETSC_MAX_PATH_LEN];
3046913077dSMatthew G. Knepley 
3059566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
3066913077dSMatthew G. Knepley       /* TODO Create names for components */
3076913077dSMatthew G. Knepley       for (c = 0; c < Nc[f]; ++c, ++l) {
3089566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(disc, &fname));
309c6a7a370SJeremy L Thompson         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
310c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
311c6a7a370SJeremy L Thompson         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
3129566063dSJacob Faibussowitsch         PetscCall(PetscStrallocpy(tmpname, &names[l]));
3136913077dSMatthew G. Knepley       }
3146913077dSMatthew G. Knepley     }
3156913077dSMatthew G. Knepley   }
3169566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
3176913077dSMatthew G. Knepley   /* Just add P_1 support for now */
3189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3199566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3209566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
3219566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
3226913077dSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
3236913077dSMatthew G. Knepley     PetscScalar *x, *svals;
3246913077dSMatthew G. Knepley 
3259566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
3266913077dSMatthew G. Knepley     for (i = 0; i < n; ++i) {
3279566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
3286913077dSMatthew G. Knepley       for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
3296913077dSMatthew G. Knepley     }
3309566063dSJacob Faibussowitsch     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
3316913077dSMatthew G. Knepley   }
3329566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
3339566063dSJacob Faibussowitsch   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
3349566063dSJacob Faibussowitsch   for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
3359566063dSJacob Faibussowitsch   PetscCall(PetscFree3(sol, names, vals));
3366913077dSMatthew G. Knepley 
3379566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDraw(lg));
3389566063dSJacob Faibussowitsch   PetscCall(PetscDrawLGDestroy(&lg));
3393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3406913077dSMatthew G. Knepley }
3416913077dSMatthew G. Knepley 
342d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
343d71ae5a4SJacob Faibussowitsch {
3446913077dSMatthew G. Knepley   DM dm;
3456913077dSMatthew G. Knepley 
3466913077dSMatthew G. Knepley   PetscFunctionBegin;
3479566063dSJacob Faibussowitsch   PetscCall(VecGetDM(u, &dm));
3489566063dSJacob Faibussowitsch   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
3493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3506913077dSMatthew G. Knepley }
3516913077dSMatthew G. Knepley 
352d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
353d71ae5a4SJacob Faibussowitsch {
354e412dcbdSMatthew G. Knepley   DM                 dm;
355d1df6f1dSMatthew G. Knepley   PetscSection       s;
356e412dcbdSMatthew G. Knepley   PetscDraw          draw, popup;
357e412dcbdSMatthew G. Knepley   DM                 cdm;
358e412dcbdSMatthew G. Knepley   PetscSection       coordSection;
359e412dcbdSMatthew G. Knepley   Vec                coordinates;
360c9c77995SMatthew G. Knepley   const PetscScalar *array;
361c9c77995SMatthew G. Knepley   PetscReal          lbound[3], ubound[3];
362339e3443SMatthew G. Knepley   PetscReal          vbound[2], time;
3636913077dSMatthew G. Knepley   PetscBool          flg;
364d1df6f1dSMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
365e412dcbdSMatthew G. Knepley   const char        *name;
366339e3443SMatthew G. Knepley   char               title[PETSC_MAX_PATH_LEN];
367e412dcbdSMatthew G. Knepley 
368e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
3699566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3709566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
3719566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
3729566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
3739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
3749566063dSJacob Faibussowitsch   PetscCall(DMGetCoarsenLevel(dm, &level));
3759566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
3769566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
3779566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
380e412dcbdSMatthew G. Knepley 
3819566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
3829566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
383e412dcbdSMatthew G. Knepley 
3849566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
385c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
3869566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
387e412dcbdSMatthew G. Knepley 
388d1df6f1dSMatthew G. Knepley   /* Could implement something like DMDASelectFields() */
389d1df6f1dSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
390d1df6f1dSMatthew G. Knepley     DM          fdm = dm;
391d1df6f1dSMatthew G. Knepley     Vec         fv  = v;
392d1df6f1dSMatthew G. Knepley     IS          fis;
393d1df6f1dSMatthew G. Knepley     char        prefix[PETSC_MAX_PATH_LEN];
394d1df6f1dSMatthew G. Knepley     const char *fname;
395d1df6f1dSMatthew G. Knepley 
3969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
3979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(s, f, &fname));
398d1df6f1dSMatthew G. Knepley 
3999566063dSJacob Faibussowitsch     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
400ad540459SPierre Jolivet     else prefix[0] = '\0';
401d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
4029566063dSJacob Faibussowitsch       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
4039566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(v, fis, &fv));
4049566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
4059566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
406d1df6f1dSMatthew G. Knepley     }
407d1df6f1dSMatthew G. Knepley     for (comp = 0; comp < Nc; ++comp, ++w) {
408d1df6f1dSMatthew G. Knepley       PetscInt nmax = 2;
409d1df6f1dSMatthew G. Knepley 
4109566063dSJacob Faibussowitsch       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
41163a3b9bcSJacob Faibussowitsch       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
41263a3b9bcSJacob Faibussowitsch       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
4139566063dSJacob Faibussowitsch       PetscCall(PetscDrawSetTitle(draw, title));
414d1df6f1dSMatthew G. Knepley 
415d1df6f1dSMatthew G. Knepley       /* TODO Get max and min only for this component */
4169566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
417339e3443SMatthew G. Knepley       if (!flg) {
4189566063dSJacob Faibussowitsch         PetscCall(VecMin(fv, NULL, &vbound[0]));
4199566063dSJacob Faibussowitsch         PetscCall(VecMax(fv, NULL, &vbound[1]));
420d1df6f1dSMatthew G. Knepley         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
421339e3443SMatthew G. Knepley       }
422c9c77995SMatthew G. Knepley 
4239566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetPopup(draw, &popup));
4249566063dSJacob Faibussowitsch       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
425c9c77995SMatthew G. Knepley       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
4269566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(fv, &array));
427e412dcbdSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
42899a2f7bcSMatthew G. Knepley         PetscScalar       *coords = NULL, *a = NULL;
429c9c77995SMatthew G. Knepley         const PetscScalar *coords_arr;
430c9c77995SMatthew G. Knepley         PetscBool          isDG;
431e56f9228SJed Brown         PetscInt           numCoords, color[4] = {-1, -1, -1, -1};
432e412dcbdSMatthew G. Knepley 
4339566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
434339e3443SMatthew G. Knepley         if (a) {
435d1df6f1dSMatthew G. Knepley           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
436339e3443SMatthew G. Knepley           color[1] = color[2] = color[3] = color[0];
437339e3443SMatthew G. Knepley         } else {
438339e3443SMatthew G. Knepley           PetscScalar *vals = NULL;
439339e3443SMatthew G. Knepley           PetscInt     numVals, va;
440339e3443SMatthew G. Knepley 
4419566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
44263a3b9bcSJacob 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);
443d1df6f1dSMatthew G. Knepley           switch (numVals / Nc) {
444d1df6f1dSMatthew G. Knepley           case 3: /* P1 Triangle */
445d1df6f1dSMatthew G. Knepley           case 4: /* P1 Quadrangle */
446d1df6f1dSMatthew G. Knepley             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
447339e3443SMatthew G. Knepley             break;
448d1df6f1dSMatthew G. Knepley           case 6: /* P2 Triangle */
449d1df6f1dSMatthew G. Knepley           case 8: /* P2 Quadrangle */
450d1df6f1dSMatthew 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]);
451d1df6f1dSMatthew G. Knepley             break;
452d71ae5a4SJacob Faibussowitsch           default:
453d71ae5a4SJacob Faibussowitsch             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
454339e3443SMatthew G. Knepley           }
4559566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
456339e3443SMatthew G. Knepley         }
457c9c77995SMatthew G. Knepley         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
458e412dcbdSMatthew G. Knepley         switch (numCoords) {
459e412dcbdSMatthew G. Knepley         case 6:
4609edc3542SMatthew Knepley         case 12: /* Localized triangle */
4619566063dSJacob 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]));
462e412dcbdSMatthew G. Knepley           break;
463e412dcbdSMatthew G. Knepley         case 8:
4649edc3542SMatthew Knepley         case 16: /* Localized quadrilateral */
4659566063dSJacob 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]));
4669566063dSJacob 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]));
467e412dcbdSMatthew G. Knepley           break;
468d71ae5a4SJacob Faibussowitsch         default:
469d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
470e412dcbdSMatthew G. Knepley         }
471c9c77995SMatthew G. Knepley         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
472e412dcbdSMatthew G. Knepley       }
4739566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(fv, &array));
4749566063dSJacob Faibussowitsch       PetscCall(PetscDrawFlush(draw));
4759566063dSJacob Faibussowitsch       PetscCall(PetscDrawPause(draw));
4769566063dSJacob Faibussowitsch       PetscCall(PetscDrawSave(draw));
477d1df6f1dSMatthew G. Knepley     }
478d1df6f1dSMatthew G. Knepley     if (Nf > 1) {
4799566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(v, fis, &fv));
4809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&fis));
4819566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&fdm));
482d1df6f1dSMatthew G. Knepley     }
483d1df6f1dSMatthew G. Knepley   }
4843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
485e412dcbdSMatthew G. Knepley }
486e412dcbdSMatthew G. Knepley 
487d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
488d71ae5a4SJacob Faibussowitsch {
4896913077dSMatthew G. Knepley   DM        dm;
4906913077dSMatthew G. Knepley   PetscDraw draw;
4916913077dSMatthew G. Knepley   PetscInt  dim;
4926913077dSMatthew G. Knepley   PetscBool isnull;
4936913077dSMatthew G. Knepley 
4946913077dSMatthew G. Knepley   PetscFunctionBegin;
4959566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
4969566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
4973ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
4986913077dSMatthew G. Knepley 
4999566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
5009566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
5016913077dSMatthew G. Knepley   switch (dim) {
502d71ae5a4SJacob Faibussowitsch   case 1:
503d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
504d71ae5a4SJacob Faibussowitsch     break;
505d71ae5a4SJacob Faibussowitsch   case 2:
506d71ae5a4SJacob Faibussowitsch     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
507d71ae5a4SJacob Faibussowitsch     break;
508d71ae5a4SJacob Faibussowitsch   default:
509d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
5106913077dSMatthew G. Knepley   }
5113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5126913077dSMatthew G. Knepley }
5136913077dSMatthew G. Knepley 
514d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
515d71ae5a4SJacob Faibussowitsch {
516684b87d9SLisandro Dalcin   DM                      dm;
517684b87d9SLisandro Dalcin   Vec                     locv;
518684b87d9SLisandro Dalcin   const char             *name;
519684b87d9SLisandro Dalcin   PetscSection            section;
520684b87d9SLisandro Dalcin   PetscInt                pStart, pEnd;
521e630c359SToby Isaac   PetscInt                numFields;
522684b87d9SLisandro Dalcin   PetscViewerVTKFieldType ft;
523684b87d9SLisandro Dalcin 
524684b87d9SLisandro Dalcin   PetscFunctionBegin;
5259566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
5269566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
5279566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)v, &name));
5289566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)locv, name));
5299566063dSJacob Faibussowitsch   PetscCall(VecCopy(v, locv));
5309566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
5319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
532e630c359SToby Isaac   if (!numFields) {
5339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
5349566063dSJacob Faibussowitsch     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
535e630c359SToby Isaac   } else {
536e630c359SToby Isaac     PetscInt f;
537e630c359SToby Isaac 
538e630c359SToby Isaac     for (f = 0; f < numFields; f++) {
5399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
540e630c359SToby Isaac       if (ft == PETSC_VTK_INVALID) continue;
5419566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)locv));
5429566063dSJacob Faibussowitsch       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
543e630c359SToby Isaac     }
5449566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locv));
545e630c359SToby Isaac   }
5463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
547684b87d9SLisandro Dalcin }
548684b87d9SLisandro Dalcin 
549d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
550d71ae5a4SJacob Faibussowitsch {
551552f7358SJed Brown   DM        dm;
5525f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;
553552f7358SJed Brown 
554552f7358SJed Brown   PetscFunctionBegin;
5559566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
55628b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
5579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
5589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5599566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5609566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
5615f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
5625f34f2dcSJed Brown   if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
563684b87d9SLisandro Dalcin     PetscInt    i, numFields;
564684b87d9SLisandro Dalcin     PetscObject fe;
565ef31f671SMatthew G. Knepley     PetscBool   fem  = PETSC_FALSE;
566684b87d9SLisandro Dalcin     Vec         locv = v;
567684b87d9SLisandro Dalcin     const char *name;
568684b87d9SLisandro Dalcin     PetscInt    step;
569684b87d9SLisandro Dalcin     PetscReal   time;
570ef31f671SMatthew G. Knepley 
5719566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &numFields));
572684b87d9SLisandro Dalcin     for (i = 0; i < numFields; i++) {
5739566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, i, NULL, &fe));
5749371c9d4SSatish Balay       if (fe->classid == PETSCFE_CLASSID) {
5759371c9d4SSatish Balay         fem = PETSC_TRUE;
5769371c9d4SSatish Balay         break;
5779371c9d4SSatish Balay       }
578ef31f671SMatthew G. Knepley     }
579684b87d9SLisandro Dalcin     if (fem) {
580798534f6SMatthew G. Knepley       PetscObject isZero;
581798534f6SMatthew G. Knepley 
5829566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &locv));
5839566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)v, &name));
5849566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)locv, name));
5859566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
5869566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
5879566063dSJacob Faibussowitsch       PetscCall(VecCopy(v, locv));
5889566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
5899566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
590ef31f671SMatthew G. Knepley     }
591552f7358SJed Brown     if (isvtk) {
5929566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
593b136c2c9SMatthew G. Knepley     } else if (ishdf5) {
594b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
5959566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
596b136c2c9SMatthew G. Knepley #else
597b136c2c9SMatthew G. Knepley       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
598b136c2c9SMatthew G. Knepley #endif
599f13a32a3SMatthew G. Knepley     } else if (isdraw) {
6009566063dSJacob Faibussowitsch       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
601684b87d9SLisandro Dalcin     } else if (isglvis) {
6029566063dSJacob Faibussowitsch       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
6039566063dSJacob Faibussowitsch       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
6049566063dSJacob Faibussowitsch       PetscCall(VecView_GLVis(locv, viewer));
6055f34f2dcSJed Brown     } else if (iscgns) {
6065f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
6075f34f2dcSJed Brown       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
6085f34f2dcSJed Brown #else
6095f34f2dcSJed Brown       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
6105f34f2dcSJed Brown #endif
611684b87d9SLisandro Dalcin     }
612798534f6SMatthew G. Knepley     if (fem) {
6139566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
6149566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &locv));
615798534f6SMatthew G. Knepley     }
616552f7358SJed Brown   } else {
617684b87d9SLisandro Dalcin     PetscBool isseq;
618684b87d9SLisandro Dalcin 
6199566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
6209566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
6219566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
622552f7358SJed Brown   }
6233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
624552f7358SJed Brown }
625552f7358SJed Brown 
626d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
627d71ae5a4SJacob Faibussowitsch {
628552f7358SJed Brown   DM        dm;
6295f34f2dcSJed Brown   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;
630552f7358SJed Brown 
631552f7358SJed Brown   PetscFunctionBegin;
6329566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
63328b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
6359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
6379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
6385f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
6399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
6405f34f2dcSJed Brown   if (isvtk || isdraw || isglvis || iscgns) {
641552f7358SJed Brown     Vec         locv;
642798534f6SMatthew G. Knepley     PetscObject isZero;
643552f7358SJed Brown     const char *name;
644552f7358SJed Brown 
6459566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &locv));
6469566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
6479566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)locv, name));
6489566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
6499566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
6509566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
6519566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
6529566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_Local(locv, viewer));
6539566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
6549566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &locv));
655b136c2c9SMatthew G. Knepley   } else if (ishdf5) {
656b136c2c9SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
6579566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
658b136c2c9SMatthew G. Knepley #else
659b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
660b136c2c9SMatthew G. Knepley #endif
6616823f3c5SBlaise Bourdin   } else if (isexodusii) {
6626823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
6639566063dSJacob Faibussowitsch     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
6646823f3c5SBlaise Bourdin #else
6656823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
6666823f3c5SBlaise Bourdin #endif
667552f7358SJed Brown   } else {
668684b87d9SLisandro Dalcin     PetscBool isseq;
669684b87d9SLisandro Dalcin 
6709566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
6719566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
6729566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
673552f7358SJed Brown   }
6743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
675552f7358SJed Brown }
676552f7358SJed Brown 
677d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
678d71ae5a4SJacob Faibussowitsch {
679d930f514SMatthew G. Knepley   DM                dm;
680d930f514SMatthew G. Knepley   MPI_Comm          comm;
681d930f514SMatthew G. Knepley   PetscViewerFormat format;
682d930f514SMatthew G. Knepley   Vec               v;
683d930f514SMatthew G. Knepley   PetscBool         isvtk, ishdf5;
684d930f514SMatthew G. Knepley 
685d930f514SMatthew G. Knepley   PetscFunctionBegin;
6869566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
6879566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
68828b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
6899566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
6909566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6919566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
692d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
693a8ad634aSStefano Zampini     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
694a8ad634aSStefano Zampini     /* this need a better fix */
695a8ad634aSStefano Zampini     if (dm->useNatural) {
696a8ad634aSStefano Zampini       if (dm->sfNatural) {
697d930f514SMatthew G. Knepley         const char *vecname;
698d930f514SMatthew G. Knepley         PetscInt    n, nroots;
699d930f514SMatthew G. Knepley 
7009566063dSJacob Faibussowitsch         PetscCall(VecGetLocalSize(originalv, &n));
7019566063dSJacob Faibussowitsch         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
702d930f514SMatthew G. Knepley         if (n == nroots) {
703f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
7049566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
7059566063dSJacob Faibussowitsch           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
7069566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
7079566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
708d930f514SMatthew G. Knepley         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
709d930f514SMatthew G. Knepley       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
710a8ad634aSStefano Zampini     } else v = originalv;
711a8ad634aSStefano Zampini   } else v = originalv;
712a8ad634aSStefano Zampini 
713d930f514SMatthew G. Knepley   if (ishdf5) {
714d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
7159566063dSJacob Faibussowitsch     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
716d930f514SMatthew G. Knepley #else
717d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
718d930f514SMatthew G. Knepley #endif
719d930f514SMatthew G. Knepley   } else if (isvtk) {
720d930f514SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
721d930f514SMatthew G. Knepley   } else {
722d930f514SMatthew G. Knepley     PetscBool isseq;
723d930f514SMatthew G. Knepley 
7249566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
7259566063dSJacob Faibussowitsch     if (isseq) PetscCall(VecView_Seq(v, viewer));
7269566063dSJacob Faibussowitsch     else PetscCall(VecView_MPI(v, viewer));
727d930f514SMatthew G. Knepley   }
728f16a8b29SMatthew G. Knepley   if (v != originalv) PetscCall(VecDestroy(&v));
7293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
730d930f514SMatthew G. Knepley }
731d930f514SMatthew G. Knepley 
732d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
733d71ae5a4SJacob Faibussowitsch {
7342c40f234SMatthew G. Knepley   DM        dm;
7352c40f234SMatthew G. Knepley   PetscBool ishdf5;
7362c40f234SMatthew G. Knepley 
7372c40f234SMatthew G. Knepley   PetscFunctionBegin;
7389566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
73928b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7409566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7412c40f234SMatthew G. Knepley   if (ishdf5) {
7422c40f234SMatthew G. Knepley     DM          dmBC;
7432c40f234SMatthew G. Knepley     Vec         gv;
7442c40f234SMatthew G. Knepley     const char *name;
7452c40f234SMatthew G. Knepley 
7469566063dSJacob Faibussowitsch     PetscCall(DMGetOutputDM(dm, &dmBC));
7479566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmBC, &gv));
7489566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)v, &name));
7499566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)gv, name));
7509566063dSJacob Faibussowitsch     PetscCall(VecLoad_Default(gv, viewer));
7519566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
7529566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
7539566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
7541baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
7553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7562c40f234SMatthew G. Knepley }
7572c40f234SMatthew G. Knepley 
758d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
759d71ae5a4SJacob Faibussowitsch {
7602c40f234SMatthew G. Knepley   DM        dm;
7616823f3c5SBlaise Bourdin   PetscBool ishdf5, isexodusii;
7622c40f234SMatthew G. Knepley 
7632c40f234SMatthew G. Knepley   PetscFunctionBegin;
7649566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
76528b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
7679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
7682c40f234SMatthew G. Knepley   if (ishdf5) {
769878b459fSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
7709566063dSJacob Faibussowitsch     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
771b136c2c9SMatthew G. Knepley #else
772b136c2c9SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
773878b459fSMatthew G. Knepley #endif
7746823f3c5SBlaise Bourdin   } else if (isexodusii) {
7756823f3c5SBlaise Bourdin #if defined(PETSC_HAVE_EXODUSII)
7769566063dSJacob Faibussowitsch     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
7776823f3c5SBlaise Bourdin #else
7786823f3c5SBlaise Bourdin     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
7796823f3c5SBlaise Bourdin #endif
7801baa6e33SBarry Smith   } else PetscCall(VecLoad_Default(v, viewer));
7813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
782552f7358SJed Brown }
783552f7358SJed Brown 
784d71ae5a4SJacob Faibussowitsch PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
785d71ae5a4SJacob Faibussowitsch {
786d930f514SMatthew G. Knepley   DM                dm;
787d930f514SMatthew G. Knepley   PetscViewerFormat format;
788d930f514SMatthew G. Knepley   PetscBool         ishdf5;
789d930f514SMatthew G. Knepley 
790d930f514SMatthew G. Knepley   PetscFunctionBegin;
7919566063dSJacob Faibussowitsch   PetscCall(VecGetDM(originalv, &dm));
79228b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
7939566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
7949566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
795d930f514SMatthew G. Knepley   if (format == PETSC_VIEWER_NATIVE) {
796a8ad634aSStefano Zampini     if (dm->useNatural) {
797d930f514SMatthew G. Knepley       if (dm->sfNatural) {
798d930f514SMatthew G. Knepley         if (ishdf5) {
799d930f514SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
800d930f514SMatthew G. Knepley           Vec         v;
801d930f514SMatthew G. Knepley           const char *vecname;
802d930f514SMatthew G. Knepley 
803f16a8b29SMatthew G. Knepley           PetscCall(DMPlexCreateNaturalVector(dm, &v));
8049566063dSJacob Faibussowitsch           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
8059566063dSJacob Faibussowitsch           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
8069566063dSJacob Faibussowitsch           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
8079566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
8089566063dSJacob Faibussowitsch           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
809f16a8b29SMatthew G. Knepley           PetscCall(VecDestroy(&v));
810d930f514SMatthew G. Knepley #else
811d930f514SMatthew G. Knepley           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
812d930f514SMatthew G. Knepley #endif
813d930f514SMatthew G. Knepley         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
814d930f514SMatthew G. Knepley       }
8151baa6e33SBarry Smith     } else PetscCall(VecLoad_Default(originalv, viewer));
816d930f514SMatthew G. Knepley   }
8173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
818d930f514SMatthew G. Knepley }
819d930f514SMatthew G. Knepley 
820d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
821d71ae5a4SJacob Faibussowitsch {
822731e8ddeSMatthew G. Knepley   PetscSection       coordSection;
823731e8ddeSMatthew G. Knepley   Vec                coordinates;
824ba2698f1SMatthew G. Knepley   DMLabel            depthLabel, celltypeLabel;
825731e8ddeSMatthew G. Knepley   const char        *name[4];
826731e8ddeSMatthew G. Knepley   const PetscScalar *a;
827731e8ddeSMatthew G. Knepley   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
828731e8ddeSMatthew G. Knepley 
829731e8ddeSMatthew G. Knepley   PetscFunctionBegin;
8309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
8319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
8329566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
8339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
8349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
8359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
8379566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &a));
838731e8ddeSMatthew G. Knepley   name[0]       = "vertex";
839731e8ddeSMatthew G. Knepley   name[1]       = "edge";
840731e8ddeSMatthew G. Knepley   name[dim - 1] = "face";
841731e8ddeSMatthew G. Knepley   name[dim]     = "cell";
842731e8ddeSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
843731e8ddeSMatthew G. Knepley     PetscInt *closure = NULL;
844ba2698f1SMatthew G. Knepley     PetscInt  closureSize, cl, ct;
845731e8ddeSMatthew G. Knepley 
8469566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
84763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
8489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
850731e8ddeSMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
851731e8ddeSMatthew G. Knepley       PetscInt point = closure[cl], depth, dof, off, d, p;
852731e8ddeSMatthew G. Knepley 
853731e8ddeSMatthew G. Knepley       if ((point < pStart) || (point >= pEnd)) continue;
8549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
855731e8ddeSMatthew G. Knepley       if (!dof) continue;
8569566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
8579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
85863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
859731e8ddeSMatthew G. Knepley       for (p = 0; p < dof / dim; ++p) {
8609566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
861731e8ddeSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
8629566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
8639566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
864731e8ddeSMatthew G. Knepley         }
8659566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
866731e8ddeSMatthew G. Knepley       }
8679566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
868731e8ddeSMatthew G. Knepley     }
8699566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
8709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
871731e8ddeSMatthew G. Knepley   }
8729566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &a));
8733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
874731e8ddeSMatthew G. Knepley }
875731e8ddeSMatthew G. Knepley 
8769371c9d4SSatish Balay typedef enum {
8779371c9d4SSatish Balay   CS_CARTESIAN,
8789371c9d4SSatish Balay   CS_POLAR,
8799371c9d4SSatish Balay   CS_CYLINDRICAL,
8809371c9d4SSatish Balay   CS_SPHERICAL
8819371c9d4SSatish Balay } CoordSystem;
88219ad8254SMatthew G. Knepley const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
88319ad8254SMatthew G. Knepley 
884d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
885d71ae5a4SJacob Faibussowitsch {
88619ad8254SMatthew G. Knepley   PetscInt i;
88719ad8254SMatthew G. Knepley 
88819ad8254SMatthew G. Knepley   PetscFunctionBegin;
88919ad8254SMatthew G. Knepley   if (dim > 3) {
8909566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
89119ad8254SMatthew G. Knepley   } else {
892bd83fdcbSStefano Zampini     PetscReal coords[3], trcoords[3] = {0., 0., 0.};
89319ad8254SMatthew G. Knepley 
89419ad8254SMatthew G. Knepley     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
89519ad8254SMatthew G. Knepley     switch (cs) {
8969371c9d4SSatish Balay     case CS_CARTESIAN:
8979371c9d4SSatish Balay       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
8989371c9d4SSatish Balay       break;
89919ad8254SMatthew G. Knepley     case CS_POLAR:
90063a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
90119ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
90219ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
90319ad8254SMatthew G. Knepley       break;
90419ad8254SMatthew G. Knepley     case CS_CYLINDRICAL:
90563a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
90619ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
90719ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
90819ad8254SMatthew G. Knepley       trcoords[2] = coords[2];
90919ad8254SMatthew G. Knepley       break;
91019ad8254SMatthew G. Knepley     case CS_SPHERICAL:
91163a3b9bcSJacob Faibussowitsch       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
91219ad8254SMatthew G. Knepley       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
91319ad8254SMatthew G. Knepley       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
91419ad8254SMatthew G. Knepley       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
91519ad8254SMatthew G. Knepley       break;
91619ad8254SMatthew G. Knepley     }
9179566063dSJacob Faibussowitsch     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
91819ad8254SMatthew G. Knepley   }
9193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92019ad8254SMatthew G. Knepley }
92119ad8254SMatthew G. Knepley 
922d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
923d71ae5a4SJacob Faibussowitsch {
924552f7358SJed Brown   DM_Plex          *mesh = (DM_Plex *)dm->data;
9256858538eSMatthew G. Knepley   DM                cdm, cdmCell;
9266858538eSMatthew G. Knepley   PetscSection      coordSection, coordSectionCell;
9276858538eSMatthew G. Knepley   Vec               coordinates, coordinatesCell;
928552f7358SJed Brown   PetscViewerFormat format;
929552f7358SJed Brown 
930552f7358SJed Brown   PetscFunctionBegin;
9319566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
932552f7358SJed Brown   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
933552f7358SJed Brown     const char *name;
934f73eea6eSMatthew G. Knepley     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
9359318fe57SMatthew G. Knepley     PetscInt    pStart, pEnd, p, numLabels, l;
936552f7358SJed Brown     PetscMPIInt rank, size;
937552f7358SJed Brown 
9389f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
9399f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
9409f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
9419f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
9429f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
9439f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
9449566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
9459566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
9469566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
9479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
9499566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
95163a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
95263a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
95363a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
95463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
9559566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
95663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
957552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
958552f7358SJed Brown       PetscInt dof, off, s;
959552f7358SJed Brown 
9609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
9619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
96248a46eb9SPierre Jolivet       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
963552f7358SJed Brown     }
9649566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
96563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
96663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
967552f7358SJed Brown     for (p = pStart; p < pEnd; ++p) {
968552f7358SJed Brown       PetscInt dof, off, c;
969552f7358SJed Brown 
9709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
9719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
97248a46eb9SPierre 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]));
973552f7358SJed Brown     }
9749566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
9759566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
9763d2e540fSStefano Zampini     if (coordSection && coordinates) {
97719ad8254SMatthew G. Knepley       CoordSystem        cs = CS_CARTESIAN;
9786858538eSMatthew G. Knepley       const PetscScalar *array, *arrayCell = NULL;
9796858538eSMatthew G. Knepley       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
98019ad8254SMatthew G. Knepley       PetscMPIInt        rank;
98119ad8254SMatthew G. Knepley       const char        *name;
98219ad8254SMatthew G. Knepley 
9839566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
9849566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
9859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
98663a3b9bcSJacob Faibussowitsch       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
9879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
9886858538eSMatthew G. Knepley       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
9896858538eSMatthew G. Knepley       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
9906858538eSMatthew G. Knepley       pStart = PetscMin(pvStart, pcStart);
9916858538eSMatthew G. Knepley       pEnd   = PetscMax(pvEnd, pcEnd);
9929566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
99363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
99463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
9959566063dSJacob Faibussowitsch       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));
99619ad8254SMatthew G. Knepley 
9979566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordinates, &array));
9986858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
9999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
10009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
100119ad8254SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
100219ad8254SMatthew G. Knepley         PetscInt dof, off;
100319ad8254SMatthew G. Knepley 
10046858538eSMatthew G. Knepley         if (p >= pvStart && p < pvEnd) {
10059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
10069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
10076858538eSMatthew G. Knepley           if (dof) {
100863a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
10099566063dSJacob Faibussowitsch             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
10109566063dSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
101119ad8254SMatthew G. Knepley           }
10126858538eSMatthew G. Knepley         }
10136858538eSMatthew G. Knepley         if (cdmCell && p >= pcStart && p < pcEnd) {
10146858538eSMatthew G. Knepley           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
10156858538eSMatthew G. Knepley           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
10166858538eSMatthew G. Knepley           if (dof) {
10176858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
10186858538eSMatthew G. Knepley             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
10196858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
10206858538eSMatthew G. Knepley           }
10216858538eSMatthew G. Knepley         }
10226858538eSMatthew G. Knepley       }
10239566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
10249566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
10259566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordinates, &array));
10266858538eSMatthew G. Knepley       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
10273d2e540fSStefano Zampini     }
10289566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
10299566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
10309318fe57SMatthew G. Knepley     for (l = 0; l < numLabels; ++l) {
10319318fe57SMatthew G. Knepley       DMLabel     label;
10329318fe57SMatthew G. Knepley       PetscBool   isdepth;
10339318fe57SMatthew G. Knepley       const char *name;
10349318fe57SMatthew G. Knepley 
10359566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
10369566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isdepth));
10379318fe57SMatthew G. Knepley       if (isdepth) continue;
10389566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
10399566063dSJacob Faibussowitsch       PetscCall(DMLabelView(label, viewer));
10409318fe57SMatthew G. Knepley     }
1041552f7358SJed Brown     if (size > 1) {
1042552f7358SJed Brown       PetscSF sf;
1043552f7358SJed Brown 
10449566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(dm, &sf));
10459566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sf, viewer));
1046552f7358SJed Brown     }
10474e2e9504SJed Brown     if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer));
10489566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1049552f7358SJed Brown   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
10500588280cSMatthew G. Knepley     const char  *name, *color;
10510588280cSMatthew G. Knepley     const char  *defcolors[3]  = {"gray", "orange", "green"};
10520588280cSMatthew G. Knepley     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
1053fe1cc32dSStefano Zampini     char         lname[PETSC_MAX_PATH_LEN];
1054552f7358SJed Brown     PetscReal    scale      = 2.0;
105578081901SStefano Zampini     PetscReal    tikzscale  = 1.0;
1056b7f6ffafSMatthew G. Knepley     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
10570588280cSMatthew G. Knepley     double       tcoords[3];
1058552f7358SJed Brown     PetscScalar *coords;
1059b7f6ffafSMatthew G. Knepley     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
1060552f7358SJed Brown     PetscMPIInt  rank, size;
10610588280cSMatthew G. Knepley     char       **names, **colors, **lcolors;
1062b7f6ffafSMatthew G. Knepley     PetscBool    flg, lflg;
1063fe1cc32dSStefano Zampini     PetscBT      wp = NULL;
1064fe1cc32dSStefano Zampini     PetscInt     pEnd, pStart;
1065552f7358SJed Brown 
10669f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
10679f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &coordSection));
10689f4ada15SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
10699f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
10709f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
10719f4ada15SMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
10729566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
10739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
10749566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
10750588280cSMatthew G. Knepley     numLabels  = PetscMax(numLabels, 10);
10760588280cSMatthew G. Knepley     numColors  = 10;
10770588280cSMatthew G. Knepley     numLColors = 10;
10789566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
10799566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
10809566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
10819566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
1082b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
1083b7f6ffafSMatthew G. Knepley     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
1084b7f6ffafSMatthew G. Knepley     n = 4;
10859566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
10861dca8a05SBarry 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);
1087*bd3611e6SMatthew G. Knepley     n = 4;
10889566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
10891dca8a05SBarry 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);
10909566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
10910588280cSMatthew G. Knepley     if (!useLabels) numLabels = 0;
10929566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
10930588280cSMatthew G. Knepley     if (!useColors) {
10940588280cSMatthew G. Knepley       numColors = 3;
10959566063dSJacob Faibussowitsch       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
10960588280cSMatthew G. Knepley     }
10979566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
10980588280cSMatthew G. Knepley     if (!useColors) {
10990588280cSMatthew G. Knepley       numLColors = 4;
11009566063dSJacob Faibussowitsch       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
11010588280cSMatthew G. Knepley     }
11029566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1103b7f6ffafSMatthew G. Knepley     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
11049566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
11051dca8a05SBarry Smith     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1106202fd40aSStefano Zampini     if (depth < dim) plotEdges = PETSC_FALSE;
11079566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
1108fe1cc32dSStefano Zampini 
1109fe1cc32dSStefano Zampini     /* filter points with labelvalue != labeldefaultvalue */
11109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
11129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
11139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1114fe1cc32dSStefano Zampini     if (lflg) {
1115fe1cc32dSStefano Zampini       DMLabel lbl;
1116fe1cc32dSStefano Zampini 
11179566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, lname, &lbl));
1118fe1cc32dSStefano Zampini       if (lbl) {
1119fe1cc32dSStefano Zampini         PetscInt val, defval;
1120fe1cc32dSStefano Zampini 
11219566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
11229566063dSJacob Faibussowitsch         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1123fe1cc32dSStefano Zampini         for (c = pStart; c < pEnd; c++) {
1124fe1cc32dSStefano Zampini           PetscInt *closure = NULL;
1125fe1cc32dSStefano Zampini           PetscInt  closureSize;
1126fe1cc32dSStefano Zampini 
11279566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(lbl, c, &val));
1128fe1cc32dSStefano Zampini           if (val == defval) continue;
1129fe1cc32dSStefano Zampini 
11309566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
113148a46eb9SPierre Jolivet           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
11329566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1133fe1cc32dSStefano Zampini         }
1134fe1cc32dSStefano Zampini       }
1135fe1cc32dSStefano Zampini     }
1136fe1cc32dSStefano Zampini 
11379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
11389566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
11399566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
11409566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\
11410588280cSMatthew G. Knepley \\documentclass[tikz]{standalone}\n\n\
1142552f7358SJed Brown \\usepackage{pgflibraryshapes}\n\
1143552f7358SJed Brown \\usetikzlibrary{backgrounds}\n\
1144552f7358SJed Brown \\usetikzlibrary{arrows}\n\
11455f80ce2aSJacob Faibussowitsch \\begin{document}\n"));
11460588280cSMatthew G. Knepley     if (size > 1) {
11479566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1148770b213bSMatthew G Knepley       for (p = 0; p < size; ++p) {
114963a3b9bcSJacob Faibussowitsch         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
115063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1151770b213bSMatthew G Knepley       }
11529566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
11530588280cSMatthew G. Knepley     }
1154b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1155b7f6ffafSMatthew G. Knepley       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart));
1156b7f6ffafSMatthew G. Knepley 
115763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
115863a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
115963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
11609566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
116163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
116263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
11639566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
116463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
116563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
116663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
116763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
11689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1169b7f6ffafSMatthew G. Knepley     }
11709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1171fe1cc32dSStefano Zampini 
1172552f7358SJed Brown     /* Plot vertices */
11739566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
11749566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1175552f7358SJed Brown     for (v = vStart; v < vEnd; ++v) {
1176552f7358SJed Brown       PetscInt  off, dof, d;
11770588280cSMatthew G. Knepley       PetscBool isLabeled = PETSC_FALSE;
1178552f7358SJed Brown 
1179fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
11809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
11819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
11829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
118363a3b9bcSJacob Faibussowitsch       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
11840588280cSMatthew G. Knepley       for (d = 0; d < dof; ++d) {
11850588280cSMatthew G. Knepley         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1186c068d9bbSLisandro Dalcin         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
11870588280cSMatthew G. Knepley       }
11880588280cSMatthew G. Knepley       /* Rotate coordinates since PGF makes z point out of the page instead of up */
11899371c9d4SSatish Balay       if (dim == 3) {
11909371c9d4SSatish Balay         PetscReal tmp = tcoords[1];
11919371c9d4SSatish Balay         tcoords[1]    = tcoords[2];
11929371c9d4SSatish Balay         tcoords[2]    = -tmp;
11939371c9d4SSatish Balay       }
1194552f7358SJed Brown       for (d = 0; d < dof; ++d) {
11959566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
11969566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1197552f7358SJed Brown       }
1198b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[0 % numColors];
1199b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
12000588280cSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
12010588280cSMatthew G. Knepley         PetscInt val;
12029566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
12039371c9d4SSatish Balay         if (val >= 0) {
12049371c9d4SSatish Balay           color     = lcolors[l % numLColors];
12059371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
12069371c9d4SSatish Balay           break;
12079371c9d4SSatish Balay         }
12080588280cSMatthew G. Knepley       }
1209b7f6ffafSMatthew G. Knepley       if (drawNumbers[0]) {
121063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1211b7f6ffafSMatthew G. Knepley       } else if (drawColors[0]) {
121263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
12131baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1214552f7358SJed Brown     }
12159566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
12169566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
1217b7f6ffafSMatthew G. Knepley     /* Plot edges */
1218b7f6ffafSMatthew G. Knepley     if (plotEdges) {
12199566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordinates, &coords));
12209566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1221b7f6ffafSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1222b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1223b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, offA, offB, dof, d;
1224b7f6ffafSMatthew G. Knepley 
1225b7f6ffafSMatthew G. Knepley         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
12269566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
122763a3b9bcSJacob Faibussowitsch         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
12289566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
12299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
12309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
12319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
12329566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1233b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1234b7f6ffafSMatthew G. Knepley           tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1235b7f6ffafSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1236b7f6ffafSMatthew G. Knepley         }
1237b7f6ffafSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
12389371c9d4SSatish Balay         if (dim == 3) {
12399371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
12409371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
12419371c9d4SSatish Balay           tcoords[2]    = -tmp;
12429371c9d4SSatish Balay         }
1243b7f6ffafSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
12449566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
12459566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1246b7f6ffafSMatthew G. Knepley         }
1247b7f6ffafSMatthew G. Knepley         if (drawHasse) color = colors[1 % numColors];
1248b7f6ffafSMatthew G. Knepley         else color = colors[rank % numColors];
1249b7f6ffafSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1250b7f6ffafSMatthew G. Knepley           PetscInt val;
1251*bd3611e6SMatthew G. Knepley           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
12529371c9d4SSatish Balay           if (val >= 0) {
12539371c9d4SSatish Balay             color = lcolors[l % numLColors];
12549371c9d4SSatish Balay             break;
12559371c9d4SSatish Balay           }
1256b7f6ffafSMatthew G. Knepley         }
125763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1258b7f6ffafSMatthew G. Knepley       }
12599566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordinates, &coords));
12609566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
12619566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1262b7f6ffafSMatthew G. Knepley     }
1263846a3e8bSMatthew G. Knepley     /* Plot cells */
1264b7f6ffafSMatthew G. Knepley     if (dim == 3 || !drawNumbers[1]) {
1265846a3e8bSMatthew G. Knepley       for (e = eStart; e < eEnd; ++e) {
1266846a3e8bSMatthew G. Knepley         const PetscInt *cone;
1267846a3e8bSMatthew G. Knepley 
1268fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1269846a3e8bSMatthew G. Knepley         color = colors[rank % numColors];
1270846a3e8bSMatthew G. Knepley         for (l = 0; l < numLabels; ++l) {
1271846a3e8bSMatthew G. Knepley           PetscInt val;
12729566063dSJacob Faibussowitsch           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
12739371c9d4SSatish Balay           if (val >= 0) {
12749371c9d4SSatish Balay             color = lcolors[l % numLColors];
12759371c9d4SSatish Balay             break;
12769371c9d4SSatish Balay           }
1277846a3e8bSMatthew G. Knepley         }
12789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, e, &cone));
127963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1280846a3e8bSMatthew G. Knepley       }
1281846a3e8bSMatthew G. Knepley     } else {
1282b7f6ffafSMatthew G. Knepley       DMPolytopeType ct;
1283846a3e8bSMatthew G. Knepley 
1284b7f6ffafSMatthew G. Knepley       /* Drawing a 2D polygon */
1285b7f6ffafSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
1286fe1cc32dSStefano Zampini         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
12879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, c, &ct));
1288c306944fSJed Brown         if (DMPolytopeTypeIsHybrid(ct)) {
1289b7f6ffafSMatthew G. Knepley           const PetscInt *cone;
1290b7f6ffafSMatthew G. Knepley           PetscInt        coneSize, e;
1291b7f6ffafSMatthew G. Knepley 
12929566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, c, &cone));
12939566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1294b7f6ffafSMatthew G. Knepley           for (e = 0; e < coneSize; ++e) {
1295b7f6ffafSMatthew G. Knepley             const PetscInt *econe;
1296b7f6ffafSMatthew G. Knepley 
12979566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
129863a3b9bcSJacob 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));
1299b7f6ffafSMatthew G. Knepley           }
1300b7f6ffafSMatthew G. Knepley         } else {
1301b7f6ffafSMatthew G. Knepley           PetscInt *closure = NULL;
1302b7f6ffafSMatthew G. Knepley           PetscInt  closureSize, Nv = 0, v;
1303b7f6ffafSMatthew G. Knepley 
13049566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1305846a3e8bSMatthew G. Knepley           for (p = 0; p < closureSize * 2; p += 2) {
1306846a3e8bSMatthew G. Knepley             const PetscInt point = closure[p];
1307846a3e8bSMatthew G. Knepley 
1308b7f6ffafSMatthew G. Knepley             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1309846a3e8bSMatthew G. Knepley           }
13109566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1311b7f6ffafSMatthew G. Knepley           for (v = 0; v <= Nv; ++v) {
1312b7f6ffafSMatthew G. Knepley             const PetscInt vertex = closure[v % Nv];
1313b7f6ffafSMatthew G. Knepley 
1314b7f6ffafSMatthew G. Knepley             if (v > 0) {
1315b7f6ffafSMatthew G. Knepley               if (plotEdges) {
1316b7f6ffafSMatthew G. Knepley                 const PetscInt *edge;
1317b7f6ffafSMatthew G. Knepley                 PetscInt        endpoints[2], ne;
1318b7f6ffafSMatthew G. Knepley 
13199371c9d4SSatish Balay                 endpoints[0] = closure[v - 1];
13209371c9d4SSatish Balay                 endpoints[1] = vertex;
13219566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
132263a3b9bcSJacob Faibussowitsch                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
132363a3b9bcSJacob Faibussowitsch                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
13249566063dSJacob Faibussowitsch                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
13251baa6e33SBarry Smith               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1326b7f6ffafSMatthew G. Knepley             }
132763a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1328b7f6ffafSMatthew G. Knepley           }
13299566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
13309566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1331846a3e8bSMatthew G. Knepley         }
1332846a3e8bSMatthew G. Knepley       }
1333b7f6ffafSMatthew G. Knepley     }
1334846a3e8bSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1335846a3e8bSMatthew G. Knepley       double             ccoords[3] = {0.0, 0.0, 0.0};
1336846a3e8bSMatthew G. Knepley       PetscBool          isLabeled  = PETSC_FALSE;
1337c713ec31SMatthew G. Knepley       PetscScalar       *cellCoords = NULL;
1338c713ec31SMatthew G. Knepley       const PetscScalar *array;
1339c713ec31SMatthew G. Knepley       PetscInt           numCoords, cdim, d;
1340c713ec31SMatthew G. Knepley       PetscBool          isDG;
1341846a3e8bSMatthew G. Knepley 
1342fe1cc32dSStefano Zampini       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1343c713ec31SMatthew G. Knepley       PetscCall(DMGetCoordinateDim(dm, &cdim));
1344c713ec31SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1345c713ec31SMatthew G. Knepley       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
13469566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1347c713ec31SMatthew G. Knepley       for (p = 0; p < numCoords / cdim; ++p) {
1348c713ec31SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
1349c713ec31SMatthew G. Knepley           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1350846a3e8bSMatthew G. Knepley           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1351846a3e8bSMatthew G. Knepley         }
1352846a3e8bSMatthew G. Knepley         /* Rotate coordinates since PGF makes z point out of the page instead of up */
13539371c9d4SSatish Balay         if (cdim == 3) {
13549371c9d4SSatish Balay           PetscReal tmp = tcoords[1];
13559371c9d4SSatish Balay           tcoords[1]    = tcoords[2];
13569371c9d4SSatish Balay           tcoords[2]    = -tmp;
13579371c9d4SSatish Balay         }
1358ad540459SPierre Jolivet         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1359846a3e8bSMatthew G. Knepley       }
1360ad540459SPierre Jolivet       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1361c713ec31SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1362c713ec31SMatthew G. Knepley       for (d = 0; d < cdim; ++d) {
13639566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
13649566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1365846a3e8bSMatthew G. Knepley       }
1366b7f6ffafSMatthew G. Knepley       if (drawHasse) color = colors[depth % numColors];
1367b7f6ffafSMatthew G. Knepley       else color = colors[rank % numColors];
1368846a3e8bSMatthew G. Knepley       for (l = 0; l < numLabels; ++l) {
1369846a3e8bSMatthew G. Knepley         PetscInt val;
13709566063dSJacob Faibussowitsch         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
13719371c9d4SSatish Balay         if (val >= 0) {
13729371c9d4SSatish Balay           color     = lcolors[l % numLColors];
13739371c9d4SSatish Balay           isLabeled = PETSC_TRUE;
13749371c9d4SSatish Balay           break;
13759371c9d4SSatish Balay         }
1376846a3e8bSMatthew G. Knepley       }
1377b7f6ffafSMatthew G. Knepley       if (drawNumbers[dim]) {
137863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1379b7f6ffafSMatthew G. Knepley       } else if (drawColors[dim]) {
138063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
13811baa6e33SBarry Smith       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1382846a3e8bSMatthew G. Knepley     }
1383b7f6ffafSMatthew G. Knepley     if (drawHasse) {
1384b7f6ffafSMatthew G. Knepley       color = colors[depth % numColors];
13859566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
13869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
13879566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
13889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
13899566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1390552f7358SJed Brown 
1391b7f6ffafSMatthew G. Knepley       color = colors[1 % numColors];
13929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
13939566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
13949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
13959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
13969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1397b7f6ffafSMatthew G. Knepley 
1398b7f6ffafSMatthew G. Knepley       color = colors[0 % numColors];
13999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
14009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
14019566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
14029566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
14039566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1404b7f6ffafSMatthew G. Knepley 
1405b7f6ffafSMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1406b7f6ffafSMatthew G. Knepley         const PetscInt *cone;
1407b7f6ffafSMatthew G. Knepley         PetscInt        coneSize, cp;
1408b7f6ffafSMatthew G. Knepley 
14099566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
14109566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
141148a46eb9SPierre 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));
14120588280cSMatthew G. Knepley       }
14130588280cSMatthew G. Knepley     }
14149566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
14159566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
14169566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
141763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
14189566063dSJacob Faibussowitsch     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
14199566063dSJacob Faibussowitsch     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
14209566063dSJacob Faibussowitsch     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
14219566063dSJacob Faibussowitsch     PetscCall(PetscFree3(names, colors, lcolors));
14229566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&wp));
14230f7d6e4aSStefano Zampini   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
14240f7d6e4aSStefano Zampini     Vec                    cown, acown;
14250f7d6e4aSStefano Zampini     VecScatter             sct;
14260f7d6e4aSStefano Zampini     ISLocalToGlobalMapping g2l;
14270f7d6e4aSStefano Zampini     IS                     gid, acis;
14280f7d6e4aSStefano Zampini     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
14290f7d6e4aSStefano Zampini     MPI_Group              ggroup, ngroup;
14300f7d6e4aSStefano Zampini     PetscScalar           *array, nid;
14310f7d6e4aSStefano Zampini     const PetscInt        *idxs;
14320f7d6e4aSStefano Zampini     PetscInt              *idxs2, *start, *adjacency, *work;
14330f7d6e4aSStefano Zampini     PetscInt64             lm[3], gm[3];
14340f7d6e4aSStefano Zampini     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
14350f7d6e4aSStefano Zampini     PetscMPIInt            d1, d2, rank;
14360f7d6e4aSStefano Zampini 
14379566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
14389566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1439b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
14409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
14410f7d6e4aSStefano Zampini #endif
14420f7d6e4aSStefano Zampini     if (ncomm != MPI_COMM_NULL) {
14439566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
14449566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
14450f7d6e4aSStefano Zampini       d1 = 0;
14469566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
14470f7d6e4aSStefano Zampini       nid = d2;
14489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ggroup));
14499566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_free(&ngroup));
14509566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_free(&ncomm));
14510f7d6e4aSStefano Zampini     } else nid = 0.0;
14520f7d6e4aSStefano Zampini 
14530f7d6e4aSStefano Zampini     /* Get connectivity */
14549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
14559566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
14560f7d6e4aSStefano Zampini 
14570f7d6e4aSStefano Zampini     /* filter overlapped local cells */
14589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
14599566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(gid, &idxs));
14609566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(gid, &cum));
14619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &idxs2));
14620f7d6e4aSStefano Zampini     for (c = cStart, cum = 0; c < cEnd; c++) {
14630f7d6e4aSStefano Zampini       if (idxs[c - cStart] < 0) continue;
14640f7d6e4aSStefano Zampini       idxs2[cum++] = idxs[c - cStart];
14650f7d6e4aSStefano Zampini     }
14669566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(gid, &idxs));
146763a3b9bcSJacob Faibussowitsch     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
14689566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
14699566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
14700f7d6e4aSStefano Zampini 
14710f7d6e4aSStefano Zampini     /* support for node-aware cell locality */
14729566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
14739566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
14749566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
14759566063dSJacob Faibussowitsch     PetscCall(VecGetArray(cown, &array));
14760f7d6e4aSStefano Zampini     for (c = 0; c < numVertices; c++) array[c] = nid;
14779566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(cown, &array));
14789566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
14799566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
14809566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
14819566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&acis));
14829566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&sct));
14839566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cown));
14840f7d6e4aSStefano Zampini 
14850f7d6e4aSStefano Zampini     /* compute edgeCut */
14860f7d6e4aSStefano Zampini     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
14879566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cum, &work));
14889566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
14899566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
14909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&gid));
14919566063dSJacob Faibussowitsch     PetscCall(VecGetArray(acown, &array));
14920f7d6e4aSStefano Zampini     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
14930f7d6e4aSStefano Zampini       PetscInt totl;
14940f7d6e4aSStefano Zampini 
14950f7d6e4aSStefano Zampini       totl = start[c + 1] - start[c];
14969566063dSJacob Faibussowitsch       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
14970f7d6e4aSStefano Zampini       for (i = 0; i < totl; i++) {
14980f7d6e4aSStefano Zampini         if (work[i] < 0) {
14990f7d6e4aSStefano Zampini           ect += 1;
15000f7d6e4aSStefano Zampini           ectn += (array[i + start[c]] != nid) ? 0 : 1;
15010f7d6e4aSStefano Zampini         }
15020f7d6e4aSStefano Zampini       }
15030f7d6e4aSStefano Zampini     }
15049566063dSJacob Faibussowitsch     PetscCall(PetscFree(work));
15059566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(acown, &array));
15060f7d6e4aSStefano Zampini     lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
15070f7d6e4aSStefano Zampini     lm[1] = -numVertices;
15081c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
150963a3b9bcSJacob 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]));
15100f7d6e4aSStefano Zampini     lm[0] = ect;                     /* edgeCut */
15110f7d6e4aSStefano Zampini     lm[1] = ectn;                    /* node-aware edgeCut */
15120f7d6e4aSStefano Zampini     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
15131c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
151463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1515b674149eSJunchao Zhang #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
151663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.));
15170f7d6e4aSStefano Zampini #else
151863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
15190f7d6e4aSStefano Zampini #endif
15209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
15219566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
15229566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
15239566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&acown));
1524552f7358SJed Brown   } else {
1525412e9a14SMatthew G. Knepley     const char    *name;
1526d80ece95SMatthew G. Knepley     PetscInt      *sizes, *hybsizes, *ghostsizes;
1527412e9a14SMatthew G. Knepley     PetscInt       locDepth, depth, cellHeight, dim, d;
1528d80ece95SMatthew G. Knepley     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1529ca7bf7eeSMatthew G. Knepley     PetscInt       numLabels, l, maxSize = 17;
15309318fe57SMatthew G. Knepley     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1531412e9a14SMatthew G. Knepley     MPI_Comm       comm;
1532412e9a14SMatthew G. Knepley     PetscMPIInt    size, rank;
1533552f7358SJed Brown 
15349566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15359566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
15369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
15379566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
15389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
15399566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
154063a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
154163a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
154263a3b9bcSJacob Faibussowitsch     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
15439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &locDepth));
15441c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
15452827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1546d80ece95SMatthew G. Knepley     gcNum = gcEnd - gcStart;
15479566063dSJacob Faibussowitsch     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
15489566063dSJacob Faibussowitsch     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1549412e9a14SMatthew G. Knepley     for (d = 0; d <= depth; d++) {
1550412e9a14SMatthew G. Knepley       PetscInt Nc[2] = {0, 0}, ict;
1551412e9a14SMatthew G. Knepley 
15529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
15539566063dSJacob Faibussowitsch       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1554412e9a14SMatthew G. Knepley       ict = ct0;
15559566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1556412e9a14SMatthew G. Knepley       ct0 = (DMPolytopeType)ict;
1557412e9a14SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
1558412e9a14SMatthew G. Knepley         DMPolytopeType ct;
1559412e9a14SMatthew G. Knepley 
15609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
1561412e9a14SMatthew G. Knepley         if (ct == ct0) ++Nc[0];
1562412e9a14SMatthew G. Knepley         else ++Nc[1];
1563412e9a14SMatthew G. Knepley       }
1564ca7bf7eeSMatthew G. Knepley       if (size < maxSize) {
15659566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
15669566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
15679566063dSJacob Faibussowitsch         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
156863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1569834065abSMatthew G. Knepley         for (p = 0; p < size; ++p) {
1570dd400576SPatrick Sanan           if (rank == 0) {
157163a3b9bcSJacob Faibussowitsch             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
157263a3b9bcSJacob Faibussowitsch             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
157363a3b9bcSJacob Faibussowitsch             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1574834065abSMatthew G. Knepley           }
1575cbb7f117SMark Adams         }
1576ca7bf7eeSMatthew G. Knepley       } else {
1577ca7bf7eeSMatthew G. Knepley         PetscInt locMinMax[2];
1578ca7bf7eeSMatthew G. Knepley 
15799371c9d4SSatish Balay         locMinMax[0] = Nc[0] + Nc[1];
15809371c9d4SSatish Balay         locMinMax[1] = Nc[0] + Nc[1];
15819566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
15829371c9d4SSatish Balay         locMinMax[0] = Nc[1];
15839371c9d4SSatish Balay         locMinMax[1] = Nc[1];
15849566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1585ca7bf7eeSMatthew G. Knepley         if (d == depth) {
15869371c9d4SSatish Balay           locMinMax[0] = gcNum;
15879371c9d4SSatish Balay           locMinMax[1] = gcNum;
15889566063dSJacob Faibussowitsch           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1589ca7bf7eeSMatthew G. Knepley         }
159063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
15919566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
15929566063dSJacob Faibussowitsch         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
15939566063dSJacob Faibussowitsch         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1594ca7bf7eeSMatthew G. Knepley       }
15959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1596552f7358SJed Brown     }
15979566063dSJacob Faibussowitsch     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
15989318fe57SMatthew G. Knepley     {
15999318fe57SMatthew G. Knepley       const PetscReal *maxCell;
16009318fe57SMatthew G. Knepley       const PetscReal *L;
16016858538eSMatthew G. Knepley       PetscBool        localized;
16029318fe57SMatthew G. Knepley 
16034fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
16049566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
16056858538eSMatthew G. Knepley       if (L || localized) {
16066858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
16079566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
16086858538eSMatthew G. Knepley         if (L) {
16096858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
16109318fe57SMatthew G. Knepley           for (d = 0; d < dim; ++d) {
16116858538eSMatthew G. Knepley             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
16126858538eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
16139318fe57SMatthew G. Knepley           }
16146858538eSMatthew G. Knepley           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
16156858538eSMatthew G. Knepley         }
16166858538eSMatthew G. Knepley         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
16179566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
16189318fe57SMatthew G. Knepley       }
16199318fe57SMatthew G. Knepley     }
16209566063dSJacob Faibussowitsch     PetscCall(DMGetNumLabels(dm, &numLabels));
16219566063dSJacob Faibussowitsch     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1622a57dd577SMatthew G Knepley     for (l = 0; l < numLabels; ++l) {
1623a57dd577SMatthew G Knepley       DMLabel         label;
1624a57dd577SMatthew G Knepley       const char     *name;
1625a57dd577SMatthew G Knepley       IS              valueIS;
1626a57dd577SMatthew G Knepley       const PetscInt *values;
1627a57dd577SMatthew G Knepley       PetscInt        numValues, v;
1628a57dd577SMatthew G Knepley 
16299566063dSJacob Faibussowitsch       PetscCall(DMGetLabelName(dm, l, &name));
16309566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
16319566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &numValues));
163263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
16339566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValueIS(label, &valueIS));
16349566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(valueIS, &values));
16359566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1636a57dd577SMatthew G Knepley       for (v = 0; v < numValues; ++v) {
1637a57dd577SMatthew G Knepley         PetscInt size;
1638a57dd577SMatthew G Knepley 
16399566063dSJacob Faibussowitsch         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
16409566063dSJacob Faibussowitsch         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
164163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1642a57dd577SMatthew G Knepley       }
16439566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
16449566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
16459566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(valueIS, &values));
16469566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&valueIS));
1647a57dd577SMatthew G Knepley     }
1648c1cad2e7SMatthew G. Knepley     {
1649c1cad2e7SMatthew G. Knepley       char    **labelNames;
1650c1cad2e7SMatthew G. Knepley       PetscInt  Nl = numLabels;
1651c1cad2e7SMatthew G. Knepley       PetscBool flg;
1652c1cad2e7SMatthew G. Knepley 
16539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nl, &labelNames));
16549566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1655c1cad2e7SMatthew G. Knepley       for (l = 0; l < Nl; ++l) {
1656c1cad2e7SMatthew G. Knepley         DMLabel label;
1657c1cad2e7SMatthew G. Knepley 
16589566063dSJacob Faibussowitsch         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1659c1cad2e7SMatthew G. Knepley         if (flg) {
16609566063dSJacob Faibussowitsch           PetscCall(DMGetLabel(dm, labelNames[l], &label));
16619566063dSJacob Faibussowitsch           PetscCall(DMLabelView(label, viewer));
1662c1cad2e7SMatthew G. Knepley         }
16639566063dSJacob Faibussowitsch         PetscCall(PetscFree(labelNames[l]));
1664c1cad2e7SMatthew G. Knepley       }
16659566063dSJacob Faibussowitsch       PetscCall(PetscFree(labelNames));
1666c1cad2e7SMatthew G. Knepley     }
166734aa8a36SMatthew G. Knepley     /* If no fields are specified, people do not want to see adjacency */
166834aa8a36SMatthew G. Knepley     if (dm->Nf) {
166934aa8a36SMatthew G. Knepley       PetscInt f;
167034aa8a36SMatthew G. Knepley 
167134aa8a36SMatthew G. Knepley       for (f = 0; f < dm->Nf; ++f) {
167234aa8a36SMatthew G. Knepley         const char *name;
167334aa8a36SMatthew G. Knepley 
16749566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
16759566063dSJacob Faibussowitsch         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
16769566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
16779566063dSJacob Faibussowitsch         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
167834aa8a36SMatthew G. Knepley         if (dm->fields[f].adjacency[0]) {
16799566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
16809566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
168134aa8a36SMatthew G. Knepley         } else {
16829566063dSJacob Faibussowitsch           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
16839566063dSJacob Faibussowitsch           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
168434aa8a36SMatthew G. Knepley         }
16859566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
168634aa8a36SMatthew G. Knepley       }
168734aa8a36SMatthew G. Knepley     }
16889566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &cdm));
16898e7ff633SMatthew G. Knepley     if (cdm) {
16909566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
16919f4ada15SMatthew G. Knepley       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
16929566063dSJacob Faibussowitsch       PetscCall(DMPlexView_Ascii(cdm, viewer));
16939566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
16948e7ff633SMatthew G. Knepley     }
1695552f7358SJed Brown   }
16963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1697552f7358SJed Brown }
1698552f7358SJed Brown 
1699d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1700d71ae5a4SJacob Faibussowitsch {
1701e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1702e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1703a12d352dSMatthew G. Knepley   PetscInt       cdim;
1704e5c487bfSMatthew G. Knepley 
1705e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
17069566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
17089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1709e5c487bfSMatthew G. Knepley   switch (ct) {
1710a12d352dSMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1711a12d352dSMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1712a12d352dSMatthew G. Knepley     switch (cdim) {
17139371c9d4SSatish Balay     case 1: {
1714a12d352dSMatthew G. Knepley       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1715a12d352dSMatthew G. Knepley       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1716a12d352dSMatthew G. Knepley 
17179566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
17189566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
17199566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
17209371c9d4SSatish Balay     } break;
17219371c9d4SSatish Balay     case 2: {
1722a12d352dSMatthew G. Knepley       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1723a12d352dSMatthew G. Knepley       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1724a12d352dSMatthew G. Knepley       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1725a12d352dSMatthew G. Knepley 
17269566063dSJacob Faibussowitsch       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17279566063dSJacob 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));
17289566063dSJacob 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));
17299371c9d4SSatish Balay     } break;
1730d71ae5a4SJacob Faibussowitsch     default:
1731d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1732a12d352dSMatthew G. Knepley     }
1733a12d352dSMatthew G. Knepley     break;
1734e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
17359371c9d4SSatish 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));
17369566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17379566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
17389566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1739e5c487bfSMatthew G. Knepley     break;
1740e5c487bfSMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
17419371c9d4SSatish 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));
17429371c9d4SSatish 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));
17439566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17449566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
17459566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
17469566063dSJacob Faibussowitsch     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1747e5c487bfSMatthew G. Knepley     break;
17489f4ada15SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
17499f4ada15SMatthew 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));
17509f4ada15SMatthew 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));
17519f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
17529f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
17539f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
17549f4ada15SMatthew G. Knepley     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
17559f4ada15SMatthew G. Knepley     break;
1756d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_FV_GHOST:
1757d71ae5a4SJacob Faibussowitsch     break;
1758d71ae5a4SJacob Faibussowitsch   default:
1759d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1760e5c487bfSMatthew G. Knepley   }
17613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1762e5c487bfSMatthew G. Knepley }
1763e5c487bfSMatthew G. Knepley 
1764d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1765d71ae5a4SJacob Faibussowitsch {
1766e5c487bfSMatthew G. Knepley   DMPolytopeType ct;
1767e5c487bfSMatthew G. Knepley   PetscReal      centroid[2] = {0., 0.};
1768e5c487bfSMatthew G. Knepley   PetscMPIInt    rank;
1769e5c487bfSMatthew G. Knepley   PetscInt       fillColor, v, e, d;
1770e5c487bfSMatthew G. Knepley 
1771e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
17729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1774e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1775e5c487bfSMatthew G. Knepley   switch (ct) {
17769371c9d4SSatish Balay   case DM_POLYTOPE_TRIANGLE: {
1777e5c487bfSMatthew G. Knepley     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1778e5c487bfSMatthew G. Knepley 
17799371c9d4SSatish Balay     for (v = 0; v < 3; ++v) {
17809371c9d4SSatish Balay       centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.;
17819371c9d4SSatish Balay       centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.;
17829371c9d4SSatish Balay     }
1783e5c487bfSMatthew G. Knepley     for (e = 0; e < 3; ++e) {
1784e5c487bfSMatthew G. Knepley       refCoords[0] = refVertices[e * 2 + 0];
1785e5c487bfSMatthew G. Knepley       refCoords[1] = refVertices[e * 2 + 1];
1786e5c487bfSMatthew G. Knepley       for (d = 1; d <= edgeDiv; ++d) {
1787e5c487bfSMatthew G. Knepley         refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv;
1788e5c487bfSMatthew G. Knepley         refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv;
1789e5c487bfSMatthew G. Knepley       }
17909566063dSJacob Faibussowitsch       PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1791e5c487bfSMatthew G. Knepley       for (d = 0; d < edgeDiv; ++d) {
17929566063dSJacob 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));
17939566063dSJacob 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));
1794e5c487bfSMatthew G. Knepley       }
1795e5c487bfSMatthew G. Knepley     }
17969371c9d4SSatish Balay   } break;
1797d71ae5a4SJacob Faibussowitsch   default:
1798d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1799e5c487bfSMatthew G. Knepley   }
18003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1801e5c487bfSMatthew G. Knepley }
1802e5c487bfSMatthew G. Knepley 
1803d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1804d71ae5a4SJacob Faibussowitsch {
1805e412dcbdSMatthew G. Knepley   PetscDraw    draw;
1806e412dcbdSMatthew G. Knepley   DM           cdm;
1807e412dcbdSMatthew G. Knepley   PetscSection coordSection;
1808e412dcbdSMatthew G. Knepley   Vec          coordinates;
1809c9c77995SMatthew G. Knepley   PetscReal    xyl[3], xyr[3];
1810e5c487bfSMatthew G. Knepley   PetscReal   *refCoords, *edgeCoords;
1811e5c487bfSMatthew G. Knepley   PetscBool    isnull, drawAffine = PETSC_TRUE;
1812c9c77995SMatthew G. Knepley   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4;
1813e412dcbdSMatthew G. Knepley 
1814e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
18159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
181663a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
18179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
18189566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
18199566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
18209566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
18219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
18229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
18239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1824e412dcbdSMatthew G. Knepley 
18259566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
18269566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
18273ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
18289566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1829e412dcbdSMatthew G. Knepley 
1830c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
18319566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
18329566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1833e412dcbdSMatthew G. Knepley 
1834cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1835cf3064d3SMatthew G. Knepley     PetscScalar       *coords = NULL;
1836c9c77995SMatthew G. Knepley     const PetscScalar *coords_arr;
1837ba2698f1SMatthew G. Knepley     PetscInt           numCoords;
1838c9c77995SMatthew G. Knepley     PetscBool          isDG;
1839cf3064d3SMatthew G. Knepley 
1840c9c77995SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
18411baa6e33SBarry Smith     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
18421baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1843c9c77995SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1844cf3064d3SMatthew G. Knepley   }
18459566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
18469566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
18479566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
18489566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
18493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1850e412dcbdSMatthew G. Knepley }
1851e412dcbdSMatthew G. Knepley 
1852e44f6aebSMatthew G. Knepley static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1853e44f6aebSMatthew G. Knepley {
1854e44f6aebSMatthew G. Knepley   DM           odm = dm, rdm = dm, cdm;
1855e44f6aebSMatthew G. Knepley   PetscFE      fe;
1856e44f6aebSMatthew G. Knepley   PetscSpace   sp;
1857e44f6aebSMatthew G. Knepley   PetscClassId id;
1858e44f6aebSMatthew G. Knepley   PetscInt     degree;
1859e44f6aebSMatthew G. Knepley   PetscBool    hoView = PETSC_TRUE;
1860e44f6aebSMatthew G. Knepley 
1861e44f6aebSMatthew G. Knepley   PetscFunctionBegin;
1862e44f6aebSMatthew G. Knepley   PetscObjectOptionsBegin((PetscObject)dm);
1863e44f6aebSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
1864e44f6aebSMatthew G. Knepley   PetscOptionsEnd();
1865e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)dm));
1866e44f6aebSMatthew G. Knepley   *hdm = dm;
1867e44f6aebSMatthew G. Knepley   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
1868e44f6aebSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
1869e44f6aebSMatthew G. Knepley   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
1870e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
1871e44f6aebSMatthew G. Knepley   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
1872e44f6aebSMatthew G. Knepley   PetscCall(PetscFEGetBasisSpace(fe, &sp));
1873e44f6aebSMatthew G. Knepley   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
1874e44f6aebSMatthew G. Knepley   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
1875e44f6aebSMatthew G. Knepley     DM  cdm, rcdm;
1876e44f6aebSMatthew G. Knepley     Mat In;
1877e44f6aebSMatthew G. Knepley     Vec cl, rcl;
1878e44f6aebSMatthew G. Knepley 
1879e44f6aebSMatthew G. Knepley     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
1880e44f6aebSMatthew G. Knepley     if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL));
1881e44f6aebSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
1882e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(odm, &cdm));
1883e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
1884e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(odm, &cl));
1885e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
1886e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoarseDM(rcdm, cdm));
1887e44f6aebSMatthew G. Knepley     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
1888e44f6aebSMatthew G. Knepley     PetscCall(MatMult(In, cl, rcl));
1889e44f6aebSMatthew G. Knepley     PetscCall(MatDestroy(&In));
1890e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
1891e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&odm));
1892e44f6aebSMatthew G. Knepley     odm = rdm;
1893e44f6aebSMatthew G. Knepley   }
1894e44f6aebSMatthew G. Knepley   *hdm = rdm;
1895e44f6aebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1896e44f6aebSMatthew G. Knepley }
1897e44f6aebSMatthew G. Knepley 
18981e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
18991e50132fSMatthew G. Knepley   #include <exodusII.h>
19006823f3c5SBlaise Bourdin   #include <petscviewerexodusii.h>
19011e50132fSMatthew G. Knepley #endif
19021e50132fSMatthew G. Knepley 
1903d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1904d71ae5a4SJacob Faibussowitsch {
19055f34f2dcSJed Brown   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1906002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
1907552f7358SJed Brown 
1908552f7358SJed Brown   PetscFunctionBegin;
1909552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1910552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19119566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
19129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
19139566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19149566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
19159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
19169566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
19175f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1918552f7358SJed Brown   if (iascii) {
19198135c375SStefano Zampini     PetscViewerFormat format;
19209566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
19211baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
19221baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
1923c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1924c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
19259566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1926c6ccd67eSMatthew G. Knepley #else
1927c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1928552f7358SJed Brown #endif
1929e412dcbdSMatthew G. Knepley   } else if (isvtk) {
19309566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1931e412dcbdSMatthew G. Knepley   } else if (isdraw) {
1932e44f6aebSMatthew G. Knepley     DM hdm;
1933e44f6aebSMatthew G. Knepley 
1934e44f6aebSMatthew G. Knepley     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
1935e44f6aebSMatthew G. Knepley     PetscCall(DMPlexView_Draw(hdm, viewer));
1936e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&hdm));
19378135c375SStefano Zampini   } else if (isglvis) {
19389566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
19391e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
19401e50132fSMatthew G. Knepley   } else if (isexodus) {
19416823f3c5SBlaise Bourdin     /*
19426823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
19436823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
1944da81f932SPierre Jolivet       with ID 1, containing all cells.
19456823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
19466823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
19476823f3c5SBlaise Bourdin     */
19486823f3c5SBlaise Bourdin     PetscInt numCS;
19499566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
19506823f3c5SBlaise Bourdin     if (!numCS) {
19511e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
19529566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
19539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
19549566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
19556823f3c5SBlaise Bourdin     }
19569566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
19571e50132fSMatthew G. Knepley #endif
19585f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
19595f34f2dcSJed Brown   } else if (iscgns) {
19605f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
19615f34f2dcSJed Brown #endif
19621baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1963cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
19649566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1965cb3ba0daSMatthew G. Knepley   if (flg) {
1966cb3ba0daSMatthew G. Knepley     Vec ranks;
19679566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
19689566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
19699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
1970cb3ba0daSMatthew G. Knepley   }
1971002a2709SMatthew G. Knepley   /* Optionally view a label */
19729566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1973002a2709SMatthew G. Knepley   if (flg) {
1974002a2709SMatthew G. Knepley     DMLabel label;
1975002a2709SMatthew G. Knepley     Vec     val;
1976002a2709SMatthew G. Knepley 
19779566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
197828b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
19799566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
19809566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
19819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
1982002a2709SMatthew G. Knepley   }
19833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1984552f7358SJed Brown }
1985552f7358SJed Brown 
19867f96f51bSksagiyam /*@
1987a1cb98faSBarry Smith   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
19887f96f51bSksagiyam 
198920f4b53cSBarry Smith   Collective
19907f96f51bSksagiyam 
19917f96f51bSksagiyam   Input Parameters:
1992a1cb98faSBarry Smith + dm     - The `DM` whose topology is to be saved
1993a1cb98faSBarry Smith - viewer - The `PetscViewer` to save it in
19947f96f51bSksagiyam 
19957f96f51bSksagiyam   Level: advanced
19967f96f51bSksagiyam 
19971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
19987f96f51bSksagiyam @*/
1999d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2000d71ae5a4SJacob Faibussowitsch {
20017f96f51bSksagiyam   PetscBool ishdf5;
20027f96f51bSksagiyam 
20037f96f51bSksagiyam   PetscFunctionBegin;
20047f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20057f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20069566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20079566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
20087f96f51bSksagiyam   if (ishdf5) {
20097f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
20107f96f51bSksagiyam     PetscViewerFormat format;
20119566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20127f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20137f96f51bSksagiyam       IS globalPointNumbering;
20147f96f51bSksagiyam 
20159566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
20169566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
20179566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
201898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
20197f96f51bSksagiyam #else
20207f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20217f96f51bSksagiyam #endif
20227f96f51bSksagiyam   }
20239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
20243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20257f96f51bSksagiyam }
20267f96f51bSksagiyam 
202777b8e257Sksagiyam /*@
2028a1cb98faSBarry Smith   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
202977b8e257Sksagiyam 
203020f4b53cSBarry Smith   Collective
203177b8e257Sksagiyam 
203277b8e257Sksagiyam   Input Parameters:
2033a1cb98faSBarry Smith + dm     - The `DM` whose coordinates are to be saved
2034a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
203577b8e257Sksagiyam 
203677b8e257Sksagiyam   Level: advanced
203777b8e257Sksagiyam 
20381cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
203977b8e257Sksagiyam @*/
2040d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2041d71ae5a4SJacob Faibussowitsch {
204277b8e257Sksagiyam   PetscBool ishdf5;
204377b8e257Sksagiyam 
204477b8e257Sksagiyam   PetscFunctionBegin;
204577b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
204677b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
204977b8e257Sksagiyam   if (ishdf5) {
205077b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
205177b8e257Sksagiyam     PetscViewerFormat format;
20529566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
205377b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20549566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
2055fe28d297SMatthew Knepley     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
205677b8e257Sksagiyam #else
205777b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
205877b8e257Sksagiyam #endif
205977b8e257Sksagiyam   }
20609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
20613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
206277b8e257Sksagiyam }
206377b8e257Sksagiyam 
2064bd6565f1Sksagiyam /*@
2065a1cb98faSBarry Smith   DMPlexLabelsView - Saves `DMPLEX` labels into a file
2066bd6565f1Sksagiyam 
206720f4b53cSBarry Smith   Collective
2068bd6565f1Sksagiyam 
2069bd6565f1Sksagiyam   Input Parameters:
2070a1cb98faSBarry Smith + dm     - The `DM` whose labels are to be saved
2071a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
2072bd6565f1Sksagiyam 
2073bd6565f1Sksagiyam   Level: advanced
2074bd6565f1Sksagiyam 
20751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2076bd6565f1Sksagiyam @*/
2077d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2078d71ae5a4SJacob Faibussowitsch {
2079bd6565f1Sksagiyam   PetscBool ishdf5;
2080bd6565f1Sksagiyam 
2081bd6565f1Sksagiyam   PetscFunctionBegin;
2082bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2083bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20849566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2086bd6565f1Sksagiyam   if (ishdf5) {
2087bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
2088bd6565f1Sksagiyam     IS                globalPointNumbering;
2089bd6565f1Sksagiyam     PetscViewerFormat format;
2090bd6565f1Sksagiyam 
20919566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2092bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20939566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
20949566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
20959566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
209698921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2097bd6565f1Sksagiyam #else
2098bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2099bd6565f1Sksagiyam #endif
2100bd6565f1Sksagiyam   }
21019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
21023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2103bd6565f1Sksagiyam }
2104bd6565f1Sksagiyam 
2105021affd3Sksagiyam /*@
2106a1cb98faSBarry Smith   DMPlexSectionView - Saves a section associated with a `DMPLEX`
2107021affd3Sksagiyam 
210820f4b53cSBarry Smith   Collective
2109021affd3Sksagiyam 
2110021affd3Sksagiyam   Input Parameters:
2111a1cb98faSBarry Smith + dm        - The `DM` that contains the topology on which the section to be saved is defined
2112a1cb98faSBarry Smith . viewer    - The `PetscViewer` for saving
2113a1cb98faSBarry Smith - sectiondm - The `DM` that contains the section to be saved
2114021affd3Sksagiyam 
2115021affd3Sksagiyam   Level: advanced
2116021affd3Sksagiyam 
2117021affd3Sksagiyam   Notes:
2118420bcc1bSBarry 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.
2119021affd3Sksagiyam 
2120420bcc1bSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2121021affd3Sksagiyam 
21221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2123021affd3Sksagiyam @*/
2124d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2125d71ae5a4SJacob Faibussowitsch {
2126021affd3Sksagiyam   PetscBool ishdf5;
2127021affd3Sksagiyam 
2128021affd3Sksagiyam   PetscFunctionBegin;
2129021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2130021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2131021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
21329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2134021affd3Sksagiyam   if (ishdf5) {
2135021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
21369566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2137021affd3Sksagiyam #else
2138021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2139021affd3Sksagiyam #endif
2140021affd3Sksagiyam   }
21419566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
21423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2143021affd3Sksagiyam }
2144021affd3Sksagiyam 
21453e97647fSksagiyam /*@
21463e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
21473e97647fSksagiyam 
214820f4b53cSBarry Smith   Collective
21493e97647fSksagiyam 
21503e97647fSksagiyam   Input Parameters:
2151a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2152a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
2153a1cb98faSBarry Smith . sectiondm - The `DM` that contains the global section on which vec is defined
21543e97647fSksagiyam - vec       - The global vector to be saved
21553e97647fSksagiyam 
21563e97647fSksagiyam   Level: advanced
21573e97647fSksagiyam 
21583e97647fSksagiyam   Notes:
2159420bcc1bSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
21603e97647fSksagiyam 
216160225df5SJacob Faibussowitsch   Calling sequence:
2162a1cb98faSBarry Smith .vb
2163a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2164a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2165a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2166a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2167a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2168a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2169a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2170a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2171a1cb98faSBarry Smith        PetscSectionSetUp(section);
2172a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2173a1cb98faSBarry Smith        PetscSectionDestroy(&section);
2174a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2175a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2176a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2177a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2178a1cb98faSBarry Smith        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2179a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2180a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2181a1cb98faSBarry Smith        DMDestroy(&dm);
2182a1cb98faSBarry Smith .ve
21833e97647fSksagiyam 
21841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
21853e97647fSksagiyam @*/
2186d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2187d71ae5a4SJacob Faibussowitsch {
21883e97647fSksagiyam   PetscBool ishdf5;
21893e97647fSksagiyam 
21903e97647fSksagiyam   PetscFunctionBegin;
21913e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21923e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21933e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
21943e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
21953e97647fSksagiyam   /* Check consistency */
21963e97647fSksagiyam   {
21973e97647fSksagiyam     PetscSection section;
21983e97647fSksagiyam     PetscBool    includesConstraints;
21993e97647fSksagiyam     PetscInt     m, m1;
22003e97647fSksagiyam 
22019566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
22029566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
22039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
22049566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
22059566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
220663a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
22073e97647fSksagiyam   }
22089566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22099566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
22103e97647fSksagiyam   if (ishdf5) {
22113e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
22129566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
22133e97647fSksagiyam #else
22143e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
22153e97647fSksagiyam #endif
22163e97647fSksagiyam   }
22179566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
22183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22193e97647fSksagiyam }
22203e97647fSksagiyam 
22213e97647fSksagiyam /*@
22223e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
22233e97647fSksagiyam 
222420f4b53cSBarry Smith   Collective
22253e97647fSksagiyam 
22263e97647fSksagiyam   Input Parameters:
2227a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2228a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
222920f4b53cSBarry Smith . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm`
22303e97647fSksagiyam - vec       - The local vector to be saved
22313e97647fSksagiyam 
22323e97647fSksagiyam   Level: advanced
22333e97647fSksagiyam 
2234a1cb98faSBarry Smith   Note:
223520f4b53cSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
22363e97647fSksagiyam 
223760225df5SJacob Faibussowitsch   Calling sequence:
2238a1cb98faSBarry Smith .vb
2239a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2240a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2241a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2242a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2243a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2244a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2245a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2246a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2247a1cb98faSBarry Smith        PetscSectionSetUp(section);
2248a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2249a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2250a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2251a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2252a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2253a1cb98faSBarry Smith        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2254a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2255a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2256a1cb98faSBarry Smith        DMDestroy(&dm);
2257a1cb98faSBarry Smith .ve
22583e97647fSksagiyam 
22591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
22603e97647fSksagiyam @*/
2261d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2262d71ae5a4SJacob Faibussowitsch {
22633e97647fSksagiyam   PetscBool ishdf5;
22643e97647fSksagiyam 
22653e97647fSksagiyam   PetscFunctionBegin;
22663e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22673e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22683e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
22693e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
22703e97647fSksagiyam   /* Check consistency */
22713e97647fSksagiyam   {
22723e97647fSksagiyam     PetscSection section;
22733e97647fSksagiyam     PetscBool    includesConstraints;
22743e97647fSksagiyam     PetscInt     m, m1;
22753e97647fSksagiyam 
22769566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
22779566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
22789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
22799566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
22809566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
228163a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
22823e97647fSksagiyam   }
22839566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22849566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
22853e97647fSksagiyam   if (ishdf5) {
22863e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
22879566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
22883e97647fSksagiyam #else
22893e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
22903e97647fSksagiyam #endif
22913e97647fSksagiyam   }
22929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
22933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22943e97647fSksagiyam }
22953e97647fSksagiyam 
2296d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2297d71ae5a4SJacob Faibussowitsch {
2298d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
22992c40f234SMatthew G. Knepley 
23002c40f234SMatthew G. Knepley   PetscFunctionBegin;
23012c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23022c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23039566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2304d4f5a9a0SVaclav Hapla   if (ishdf5) {
23052c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
23069c48423bSVaclav Hapla     PetscViewerFormat format;
23079566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
23089c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
23099566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2310509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
23119566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
231298921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
23133ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
23142c40f234SMatthew G. Knepley #else
23152c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2316552f7358SJed Brown #endif
231798921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2318552f7358SJed Brown }
2319552f7358SJed Brown 
2320ea8e1828Sksagiyam /*@
2321a1cb98faSBarry Smith   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2322ea8e1828Sksagiyam 
232320f4b53cSBarry Smith   Collective
2324ea8e1828Sksagiyam 
2325ea8e1828Sksagiyam   Input Parameters:
2326a1cb98faSBarry Smith + dm     - The `DM` into which the topology is loaded
2327a1cb98faSBarry Smith - viewer - The `PetscViewer` for the saved topology
2328ea8e1828Sksagiyam 
23292fe279fdSBarry Smith   Output Parameter:
233020f4b53cSBarry 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; `NULL` if unneeded
2331dec9e869Sksagiyam 
2332ea8e1828Sksagiyam   Level: advanced
2333ea8e1828Sksagiyam 
23341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2335a1cb98faSBarry Smith           `PetscViewer`, `PetscSF`
2336ea8e1828Sksagiyam @*/
2337d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2338d71ae5a4SJacob Faibussowitsch {
2339ea8e1828Sksagiyam   PetscBool ishdf5;
2340ea8e1828Sksagiyam 
2341ea8e1828Sksagiyam   PetscFunctionBegin;
2342ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2343ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23444f572ea9SToby Isaac   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
23459566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2347ea8e1828Sksagiyam   if (ishdf5) {
2348ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2349ea8e1828Sksagiyam     PetscViewerFormat format;
23509566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2351ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
23529566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
235398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2354ea8e1828Sksagiyam #else
2355ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2356ea8e1828Sksagiyam #endif
2357ea8e1828Sksagiyam   }
23589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
23593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2360ea8e1828Sksagiyam }
2361ea8e1828Sksagiyam 
23623e701f1cSksagiyam /*@
2363a1cb98faSBarry Smith   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
23643e701f1cSksagiyam 
236520f4b53cSBarry Smith   Collective
23663e701f1cSksagiyam 
23673e701f1cSksagiyam   Input Parameters:
2368a1cb98faSBarry Smith + dm                   - The `DM` into which the coordinates are loaded
2369a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved coordinates
2370a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
23713e701f1cSksagiyam 
23723e701f1cSksagiyam   Level: advanced
23733e701f1cSksagiyam 
23741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2375a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
23763e701f1cSksagiyam @*/
2377d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2378d71ae5a4SJacob Faibussowitsch {
23793e701f1cSksagiyam   PetscBool ishdf5;
23803e701f1cSksagiyam 
23813e701f1cSksagiyam   PetscFunctionBegin;
23823e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23833e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2384c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
23859566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
23873e701f1cSksagiyam   if (ishdf5) {
23883e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
23893e701f1cSksagiyam     PetscViewerFormat format;
23909566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
23913e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
23929566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
239398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
23943e701f1cSksagiyam #else
23953e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23963e701f1cSksagiyam #endif
23973e701f1cSksagiyam   }
23989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
23993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24003e701f1cSksagiyam }
24013e701f1cSksagiyam 
2402b08ad5deSksagiyam /*@
2403a1cb98faSBarry Smith   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2404b08ad5deSksagiyam 
240520f4b53cSBarry Smith   Collective
2406b08ad5deSksagiyam 
2407b08ad5deSksagiyam   Input Parameters:
2408a1cb98faSBarry Smith + dm                   - The `DM` into which the labels are loaded
2409a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved labels
241020f4b53cSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2411b08ad5deSksagiyam 
2412b08ad5deSksagiyam   Level: advanced
2413b08ad5deSksagiyam 
2414a1cb98faSBarry Smith   Note:
2415a1cb98faSBarry Smith   The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs.
2416e6368b79SVaclav Hapla 
24171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2418a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
2419b08ad5deSksagiyam @*/
2420d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2421d71ae5a4SJacob Faibussowitsch {
2422b08ad5deSksagiyam   PetscBool ishdf5;
2423b08ad5deSksagiyam 
2424b08ad5deSksagiyam   PetscFunctionBegin;
2425b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2426b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2427e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
24289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2430b08ad5deSksagiyam   if (ishdf5) {
2431b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2432b08ad5deSksagiyam     PetscViewerFormat format;
2433b08ad5deSksagiyam 
24349566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2435b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24369566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
243798921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2438b08ad5deSksagiyam #else
2439b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2440b08ad5deSksagiyam #endif
2441b08ad5deSksagiyam   }
24429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
24433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2444b08ad5deSksagiyam }
2445b08ad5deSksagiyam 
2446f84dd6b4Sksagiyam /*@
2447a1cb98faSBarry Smith   DMPlexSectionLoad - Loads section into a `DMPLEX`
2448f84dd6b4Sksagiyam 
244920f4b53cSBarry Smith   Collective
2450f84dd6b4Sksagiyam 
2451f84dd6b4Sksagiyam   Input Parameters:
2452a1cb98faSBarry Smith + dm                   - The `DM` that represents the topology
2453a1cb98faSBarry Smith . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
2454a1cb98faSBarry Smith . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated
2455a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2456f84dd6b4Sksagiyam 
2457a4e35b19SJacob Faibussowitsch   Output Parameters:
245820f4b53cSBarry 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)
245920f4b53cSBarry 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)
2460f84dd6b4Sksagiyam 
2461f84dd6b4Sksagiyam   Level: advanced
2462f84dd6b4Sksagiyam 
2463f84dd6b4Sksagiyam   Notes:
246420f4b53cSBarry 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.
2465f84dd6b4Sksagiyam 
246620f4b53cSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2467f84dd6b4Sksagiyam 
246820f4b53cSBarry 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.
2469f84dd6b4Sksagiyam 
2470f84dd6b4Sksagiyam   Example using 2 processes:
2471a1cb98faSBarry Smith .vb
2472a1cb98faSBarry Smith   NX (number of points on dm): 4
2473a1cb98faSBarry Smith   sectionA                   : the on-disk section
2474a1cb98faSBarry Smith   vecA                       : a vector associated with sectionA
2475a1cb98faSBarry Smith   sectionB                   : sectiondm's local section constructed in this function
2476a1cb98faSBarry Smith   vecB (local)               : a vector associated with sectiondm's local section
2477a1cb98faSBarry Smith   vecB (global)              : a vector associated with sectiondm's global section
2478f84dd6b4Sksagiyam 
2479a1cb98faSBarry Smith                                      rank 0    rank 1
2480a1cb98faSBarry Smith   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2481a1cb98faSBarry Smith   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2482a1cb98faSBarry Smith   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2483a1cb98faSBarry Smith   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2484a1cb98faSBarry Smith   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2485a1cb98faSBarry Smith   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2486a1cb98faSBarry Smith   sectionB->atlasDof             :     1 0 1 | 1 3
2487a1cb98faSBarry Smith   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2488a1cb98faSBarry Smith   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2489a1cb98faSBarry Smith   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2490a1cb98faSBarry Smith .ve
2491a1cb98faSBarry Smith   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2492a1cb98faSBarry Smith 
24931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2494f84dd6b4Sksagiyam @*/
2495d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2496d71ae5a4SJacob Faibussowitsch {
2497f84dd6b4Sksagiyam   PetscBool ishdf5;
2498f84dd6b4Sksagiyam 
2499f84dd6b4Sksagiyam   PetscFunctionBegin;
2500f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2501f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2502f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2503f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
25044f572ea9SToby Isaac   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
25054f572ea9SToby Isaac   if (localDofSF) PetscAssertPointer(localDofSF, 6);
25069566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25079566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2508f84dd6b4Sksagiyam   if (ishdf5) {
2509f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
25109566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2511f84dd6b4Sksagiyam #else
2512f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2513f84dd6b4Sksagiyam #endif
2514f84dd6b4Sksagiyam   }
25159566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
25163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2517f84dd6b4Sksagiyam }
2518f84dd6b4Sksagiyam 
25198be3dfe1Sksagiyam /*@
25208be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
25218be3dfe1Sksagiyam 
252220f4b53cSBarry Smith   Collective
25238be3dfe1Sksagiyam 
25248be3dfe1Sksagiyam   Input Parameters:
2525a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2526a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
2527a1cb98faSBarry Smith . sectiondm - The `DM` that contains the global section on which vec is defined
2528a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
25298be3dfe1Sksagiyam - vec       - The global vector to set values of
25308be3dfe1Sksagiyam 
25318be3dfe1Sksagiyam   Level: advanced
25328be3dfe1Sksagiyam 
25338be3dfe1Sksagiyam   Notes:
2534a1cb98faSBarry Smith   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
25358be3dfe1Sksagiyam 
253660225df5SJacob Faibussowitsch   Calling sequence:
2537a1cb98faSBarry Smith .vb
2538a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2539a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2540a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2541a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2542a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2543a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2544a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2545a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2546a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2547a1cb98faSBarry Smith        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2548a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2549a1cb98faSBarry Smith        PetscSFDestroy(&gsf);
2550a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2551a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2552a1cb98faSBarry Smith        DMDestroy(&dm);
2553a1cb98faSBarry Smith .ve
25548be3dfe1Sksagiyam 
25551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2556a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
25578be3dfe1Sksagiyam @*/
2558d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2559d71ae5a4SJacob Faibussowitsch {
25608be3dfe1Sksagiyam   PetscBool ishdf5;
25618be3dfe1Sksagiyam 
25628be3dfe1Sksagiyam   PetscFunctionBegin;
25638be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25648be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
25658be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
25668be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
25678be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
25688be3dfe1Sksagiyam   /* Check consistency */
25698be3dfe1Sksagiyam   {
25708be3dfe1Sksagiyam     PetscSection section;
25718be3dfe1Sksagiyam     PetscBool    includesConstraints;
25728be3dfe1Sksagiyam     PetscInt     m, m1;
25738be3dfe1Sksagiyam 
25749566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
25759566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
25769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
25779566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
25789566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
257963a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
25808be3dfe1Sksagiyam   }
25819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
25838be3dfe1Sksagiyam   if (ishdf5) {
25848be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
25859566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
25868be3dfe1Sksagiyam #else
25878be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
25888be3dfe1Sksagiyam #endif
25898be3dfe1Sksagiyam   }
25909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
25913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25928be3dfe1Sksagiyam }
25938be3dfe1Sksagiyam 
25948be3dfe1Sksagiyam /*@
25958be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
25968be3dfe1Sksagiyam 
259720f4b53cSBarry Smith   Collective
25988be3dfe1Sksagiyam 
25998be3dfe1Sksagiyam   Input Parameters:
2600a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2601a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
2602a1cb98faSBarry Smith . sectiondm - The `DM` that contains the local section on which vec is defined
2603a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
26048be3dfe1Sksagiyam - vec       - The local vector to set values of
26058be3dfe1Sksagiyam 
26068be3dfe1Sksagiyam   Level: advanced
26078be3dfe1Sksagiyam 
26088be3dfe1Sksagiyam   Notes:
260920f4b53cSBarry Smith   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
26108be3dfe1Sksagiyam 
261160225df5SJacob Faibussowitsch   Calling sequence:
2612a1cb98faSBarry Smith .vb
2613a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2614a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2615a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2616a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2617a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2618a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2619a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2620a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2621a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2622a1cb98faSBarry Smith        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2623a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2624a1cb98faSBarry Smith        PetscSFDestroy(&lsf);
2625a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2626a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2627a1cb98faSBarry Smith        DMDestroy(&dm);
2628a1cb98faSBarry Smith .ve
26298be3dfe1Sksagiyam 
26301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2631a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
26328be3dfe1Sksagiyam @*/
2633d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2634d71ae5a4SJacob Faibussowitsch {
26358be3dfe1Sksagiyam   PetscBool ishdf5;
26368be3dfe1Sksagiyam 
26378be3dfe1Sksagiyam   PetscFunctionBegin;
26388be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26398be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
26408be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
26418be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
26428be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
26438be3dfe1Sksagiyam   /* Check consistency */
26448be3dfe1Sksagiyam   {
26458be3dfe1Sksagiyam     PetscSection section;
26468be3dfe1Sksagiyam     PetscBool    includesConstraints;
26478be3dfe1Sksagiyam     PetscInt     m, m1;
26488be3dfe1Sksagiyam 
26499566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
26509566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
26519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
26529566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
26539566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
265463a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
26558be3dfe1Sksagiyam   }
26569566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
26579566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
26588be3dfe1Sksagiyam   if (ishdf5) {
26598be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
26609566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
26618be3dfe1Sksagiyam #else
26628be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
26638be3dfe1Sksagiyam #endif
26648be3dfe1Sksagiyam   }
26659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
26663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26678be3dfe1Sksagiyam }
26688be3dfe1Sksagiyam 
2669d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2670d71ae5a4SJacob Faibussowitsch {
2671552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2672552f7358SJed Brown 
2673552f7358SJed Brown   PetscFunctionBegin;
26749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
26759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
26769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
26779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
26786c51210dSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
26792e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
26802e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
26812e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
26822e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
26836bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
26846bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2685c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2686c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2687d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2688d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
26895f06a3ddSJed Brown   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
26903ba16761SJacob Faibussowitsch   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
26919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
26929566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
26939566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
26949566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
26959566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
26969566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
269721027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
26989f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
26999566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
27009566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
27019566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
27021d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
27039566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
27049566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
27059566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
27069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
27079566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
27084e2e9504SJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.face_sf));
27096725e60dSJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
27106725e60dSJed Brown   PetscCall(ISDestroy(&mesh->periodic.periodic_points));
27119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
27129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
27139566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
27149566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
27159566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
27169566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
27179566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
27189566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
27199566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
27209566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
27219566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2722552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
27239566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
27243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2725552f7358SJed Brown }
2726552f7358SJed Brown 
2727d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2728d71ae5a4SJacob Faibussowitsch {
27298d1174e4SMatthew G. Knepley   PetscSection           sectionGlobal;
2730acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
27319fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2732837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2733b412c318SBarry Smith   MatType                mtype;
27341428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2735552f7358SJed Brown 
2736552f7358SJed Brown   PetscFunctionBegin;
27379566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2738b412c318SBarry Smith   mtype = dm->mattype;
27399566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
27409566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
27419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
27429fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
27439566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
27449566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
27459566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
27469566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
27479566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2748acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
27499566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
27509566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
27519566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
27529566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
27539566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
27549566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
27559566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
27569566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2757552f7358SJed Brown   if (!isShell) {
2758837628f4SStefano Zampini     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
27599fca9976SJed Brown     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2760863027abSJed Brown     PetscInt  pStart, pEnd, p, dof, cdof, num_fields;
2761552f7358SJed Brown 
27629566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
27639fca9976SJed Brown 
27649fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
27659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2766863027abSJed Brown     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2767e432b41dSStefano Zampini     for (p = pStart; p < pEnd; ++p) {
2768863027abSJed Brown       switch (dm->blocking_type) {
27690e762ea3SJed Brown       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
27709fca9976SJed Brown         PetscInt bdof, offset;
2771a9d99c84SMatthew G. Knepley 
27729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
27739fca9976SJed Brown         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
27749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
27759371c9d4SSatish Balay         for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof;
27761d17a0a3SMatthew G. Knepley         dof  = dof < 0 ? -(dof + 1) : dof;
27771d17a0a3SMatthew G. Knepley         bdof = cdof && (dof - cdof) ? 1 : dof;
27781d17a0a3SMatthew G. Knepley         if (dof) {
27799371c9d4SSatish Balay           if (bs < 0) {
27809371c9d4SSatish Balay             bs = bdof;
27819371c9d4SSatish Balay           } else if (bs != bdof) {
27829371c9d4SSatish Balay             bs = 1;
27839371c9d4SSatish Balay           }
2784552f7358SJed Brown         }
2785863027abSJed Brown       } break;
2786863027abSJed Brown       case DM_BLOCKING_FIELD_NODE: {
2787863027abSJed Brown         for (PetscInt field = 0; field < num_fields; field++) {
2788863027abSJed Brown           PetscInt num_comp, bdof, offset;
2789863027abSJed Brown           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2790863027abSJed Brown           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2791863027abSJed Brown           if (dof < 0) continue;
2792863027abSJed Brown           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2793863027abSJed Brown           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2794863027abSJed 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);
2795863027abSJed Brown           PetscInt num_nodes = dof / num_comp;
2796863027abSJed Brown           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2797863027abSJed Brown           // Handle possibly constant block size (unlikely)
2798863027abSJed Brown           bdof = cdof && (dof - cdof) ? 1 : dof;
2799863027abSJed Brown           if (dof) {
2800863027abSJed Brown             if (bs < 0) {
2801863027abSJed Brown               bs = bdof;
2802863027abSJed Brown             } else if (bs != bdof) {
2803863027abSJed Brown               bs = 1;
2804863027abSJed Brown             }
2805863027abSJed Brown           }
2806863027abSJed Brown         }
2807863027abSJed Brown       } break;
2808863027abSJed Brown       }
28092a28c762SMatthew G Knepley     }
28102a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2811e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2812e432b41dSStefano Zampini     bsLocal[1] = bs;
28139566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2814e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2815e432b41dSStefano Zampini     else bs = bsMinMax[0];
28166fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
28179566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
28180682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
28199566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
28209566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
28210682b8bbSJed Brown     } else {
28229566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
28239566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
28249566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2825552f7358SJed Brown     }
28269fca9976SJed Brown     { // Consolidate blocks
28279fca9976SJed Brown       PetscInt nblocks = 0;
28289fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
28299fca9976SJed Brown         if (pblocks[i] == 0) continue;
28309fca9976SJed Brown         pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2831ad540459SPierre Jolivet         for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]);
28329fca9976SJed Brown       }
28339fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
28349fca9976SJed Brown     }
28359fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2836aa0f6e3cSJed Brown   }
28379566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
28383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2839552f7358SJed Brown }
2840552f7358SJed Brown 
28417cd05799SMatthew G. Knepley /*@
2842a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2843be36d101SStefano Zampini 
2844a1cb98faSBarry Smith   Not Collective
2845be36d101SStefano Zampini 
2846be36d101SStefano Zampini   Input Parameter:
284760225df5SJacob Faibussowitsch . dm - The `DMPLEX`
2848be36d101SStefano Zampini 
28492fe279fdSBarry Smith   Output Parameter:
2850be36d101SStefano Zampini . subsection - The subdomain section
2851be36d101SStefano Zampini 
2852be36d101SStefano Zampini   Level: developer
2853be36d101SStefano Zampini 
28541cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
28557cd05799SMatthew G. Knepley @*/
2856d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2857d71ae5a4SJacob Faibussowitsch {
2858be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
2859be36d101SStefano Zampini 
2860be36d101SStefano Zampini   PetscFunctionBegin;
2861be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2862be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2863be36d101SStefano Zampini     PetscSection section;
2864be36d101SStefano Zampini     PetscSF      sf;
2865be36d101SStefano Zampini 
28669566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
28679566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
28689566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
28699566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2870be36d101SStefano Zampini   }
2871be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
28723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2873be36d101SStefano Zampini }
2874be36d101SStefano Zampini 
2875552f7358SJed Brown /*@
287620f4b53cSBarry Smith   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
2877552f7358SJed Brown 
2878a1cb98faSBarry Smith   Not Collective
2879552f7358SJed Brown 
2880552f7358SJed Brown   Input Parameter:
288160225df5SJacob Faibussowitsch . dm - The `DMPLEX`
2882552f7358SJed Brown 
2883552f7358SJed Brown   Output Parameters:
2884552f7358SJed Brown + pStart - The first mesh point
2885552f7358SJed Brown - pEnd   - The upper bound for mesh points
2886552f7358SJed Brown 
2887552f7358SJed Brown   Level: beginner
2888552f7358SJed Brown 
28891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2890552f7358SJed Brown @*/
2891d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2892d71ae5a4SJacob Faibussowitsch {
2893552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2894552f7358SJed Brown 
2895552f7358SJed Brown   PetscFunctionBegin;
2896552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28979f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
28989f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
28993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2900552f7358SJed Brown }
2901552f7358SJed Brown 
2902552f7358SJed Brown /*@
290320f4b53cSBarry Smith   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
2904552f7358SJed Brown 
2905a1cb98faSBarry Smith   Not Collective
2906552f7358SJed Brown 
2907552f7358SJed Brown   Input Parameters:
290860225df5SJacob Faibussowitsch + dm     - The `DMPLEX`
2909552f7358SJed Brown . pStart - The first mesh point
2910552f7358SJed Brown - pEnd   - The upper bound for mesh points
2911552f7358SJed Brown 
2912552f7358SJed Brown   Level: beginner
2913552f7358SJed Brown 
29141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2915552f7358SJed Brown @*/
2916d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2917d71ae5a4SJacob Faibussowitsch {
2918552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2919552f7358SJed Brown 
2920552f7358SJed Brown   PetscFunctionBegin;
2921552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
29229566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
29239566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
292421027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
29253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2926552f7358SJed Brown }
2927552f7358SJed Brown 
2928552f7358SJed Brown /*@
2929eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2930552f7358SJed Brown 
2931a1cb98faSBarry Smith   Not Collective
2932552f7358SJed Brown 
2933552f7358SJed Brown   Input Parameters:
293460225df5SJacob Faibussowitsch + dm - The `DMPLEX`
2935a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
2936552f7358SJed Brown 
2937552f7358SJed Brown   Output Parameter:
293820f4b53cSBarry Smith . size - The cone size for point `p`
2939552f7358SJed Brown 
2940552f7358SJed Brown   Level: beginner
2941552f7358SJed Brown 
29421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2943552f7358SJed Brown @*/
2944d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2945d71ae5a4SJacob Faibussowitsch {
2946552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2947552f7358SJed Brown 
2948552f7358SJed Brown   PetscFunctionBegin;
2949552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
29504f572ea9SToby Isaac   PetscAssertPointer(size, 3);
29519f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
29529f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
29533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2954552f7358SJed Brown }
2955552f7358SJed Brown 
2956552f7358SJed Brown /*@
2957eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2958552f7358SJed Brown 
2959a1cb98faSBarry Smith   Not Collective
2960552f7358SJed Brown 
2961552f7358SJed Brown   Input Parameters:
296260225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
2963a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
296420f4b53cSBarry Smith - size - The cone size for point `p`
2965552f7358SJed Brown 
2966552f7358SJed Brown   Level: beginner
2967552f7358SJed Brown 
2968a1cb98faSBarry Smith   Note:
2969a1cb98faSBarry Smith   This should be called after `DMPlexSetChart()`.
2970a1cb98faSBarry Smith 
29711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2972552f7358SJed Brown @*/
2973d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2974d71ae5a4SJacob Faibussowitsch {
2975552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2976552f7358SJed Brown 
2977552f7358SJed Brown   PetscFunctionBegin;
2978552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
29799f4ada15SMatthew G. Knepley   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
29809566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
29813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2982552f7358SJed Brown }
2983552f7358SJed Brown 
2984552f7358SJed Brown /*@C
2985eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2986552f7358SJed Brown 
2987a1cb98faSBarry Smith   Not Collective
2988552f7358SJed Brown 
2989552f7358SJed Brown   Input Parameters:
2990a1cb98faSBarry Smith + dm - The `DMPLEX`
2991a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
2992552f7358SJed Brown 
2993552f7358SJed Brown   Output Parameter:
299420f4b53cSBarry Smith . cone - An array of points which are on the in-edges for point `p`
2995552f7358SJed Brown 
2996552f7358SJed Brown   Level: beginner
2997552f7358SJed Brown 
299860225df5SJacob Faibussowitsch   Fortran Notes:
2999a1cb98faSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
3000a1cb98faSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
30013813dfbdSMatthew G Knepley 
30021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3003552f7358SJed Brown @*/
3004d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3005d71ae5a4SJacob Faibussowitsch {
3006552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3007552f7358SJed Brown   PetscInt off;
3008552f7358SJed Brown 
3009552f7358SJed Brown   PetscFunctionBegin;
3010552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30114f572ea9SToby Isaac   PetscAssertPointer(cone, 3);
30129566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3013552f7358SJed Brown   *cone = &mesh->cones[off];
30143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3015552f7358SJed Brown }
3016552f7358SJed Brown 
30170ce7577fSVaclav Hapla /*@C
30180ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
30190ce7577fSVaclav Hapla 
3020a1cb98faSBarry Smith   Not Collective
30210ce7577fSVaclav Hapla 
30220ce7577fSVaclav Hapla   Input Parameters:
3023a1cb98faSBarry Smith + dm - The `DMPLEX`
3024a1cb98faSBarry Smith - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
30250ce7577fSVaclav Hapla 
3026d8d19677SJose E. Roman   Output Parameters:
302720f4b53cSBarry Smith + pConesSection - `PetscSection` describing the layout of `pCones`
302820f4b53cSBarry Smith - pCones        - An array of points which are on the in-edges for the point set `p`
30290ce7577fSVaclav Hapla 
30300ce7577fSVaclav Hapla   Level: intermediate
30310ce7577fSVaclav Hapla 
30321cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
30330ce7577fSVaclav Hapla @*/
3034d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
3035d71ae5a4SJacob Faibussowitsch {
30360ce7577fSVaclav Hapla   PetscSection cs, newcs;
30370ce7577fSVaclav Hapla   PetscInt    *cones;
30380ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
30390ce7577fSVaclav Hapla   PetscInt     n;
30400ce7577fSVaclav Hapla 
30410ce7577fSVaclav Hapla   PetscFunctionBegin;
30429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
30439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
30449566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
30450ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
30460ce7577fSVaclav Hapla   if (pCones) {
30479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
30489566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
30490ce7577fSVaclav Hapla   }
30503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30510ce7577fSVaclav Hapla }
30520ce7577fSVaclav Hapla 
3053af9eab45SVaclav Hapla /*@
3054af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
3055d4636a37SVaclav Hapla 
3056a1cb98faSBarry Smith   Not Collective
3057d4636a37SVaclav Hapla 
3058d4636a37SVaclav Hapla   Input Parameters:
3059a1cb98faSBarry Smith + dm     - The `DMPLEX`
3060a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3061d4636a37SVaclav Hapla 
3062d4636a37SVaclav Hapla   Output Parameter:
3063af9eab45SVaclav Hapla . expandedPoints - An array of vertices recursively expanded from input points
3064d4636a37SVaclav Hapla 
3065d4636a37SVaclav Hapla   Level: advanced
3066d4636a37SVaclav Hapla 
3067af9eab45SVaclav Hapla   Notes:
306820f4b53cSBarry Smith   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
3069af9eab45SVaclav Hapla 
3070a1cb98faSBarry Smith   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
3071a1cb98faSBarry Smith 
30721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3073a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`
3074d4636a37SVaclav Hapla @*/
3075d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3076d71ae5a4SJacob Faibussowitsch {
3077af9eab45SVaclav Hapla   IS      *expandedPointsAll;
3078af9eab45SVaclav Hapla   PetscInt depth;
3079d4636a37SVaclav Hapla 
3080d4636a37SVaclav Hapla   PetscFunctionBegin;
3081af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3082af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
30834f572ea9SToby Isaac   PetscAssertPointer(expandedPoints, 3);
30849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3085af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
30869566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
30879566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
30883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3089af9eab45SVaclav Hapla }
3090af9eab45SVaclav Hapla 
3091af9eab45SVaclav Hapla /*@
3092af9eab45SVaclav Hapla   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones).
3093af9eab45SVaclav Hapla 
3094a1cb98faSBarry Smith   Not Collective
3095af9eab45SVaclav Hapla 
3096af9eab45SVaclav Hapla   Input Parameters:
3097a1cb98faSBarry Smith + dm     - The `DMPLEX`
3098a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3099af9eab45SVaclav Hapla 
3100d8d19677SJose E. Roman   Output Parameters:
3101a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3102af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
3103af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3104af9eab45SVaclav Hapla 
3105af9eab45SVaclav Hapla   Level: advanced
3106af9eab45SVaclav Hapla 
3107af9eab45SVaclav Hapla   Notes:
3108a1cb98faSBarry Smith   Like `DMPlexGetConeTuple()` but recursive.
3109af9eab45SVaclav Hapla 
3110a4e35b19SJacob 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.
3111af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
3112af9eab45SVaclav Hapla 
3113a4e35b19SJacob 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\:
3114a4e35b19SJacob Faibussowitsch   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3115a4e35b19SJacob Faibussowitsch   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
3116af9eab45SVaclav Hapla 
31171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3118a1cb98faSBarry Smith           `DMPlexGetDepth()`, `PetscSection`, `IS`
3119af9eab45SVaclav Hapla @*/
3120d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3121d71ae5a4SJacob Faibussowitsch {
3122af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
3123af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
3124af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3125af9eab45SVaclav Hapla   IS             *expandedPoints_;
3126af9eab45SVaclav Hapla   PetscSection   *sections_;
3127af9eab45SVaclav Hapla 
3128af9eab45SVaclav Hapla   PetscFunctionBegin;
3129af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3130af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
31314f572ea9SToby Isaac   if (depth) PetscAssertPointer(depth, 3);
31324f572ea9SToby Isaac   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
31334f572ea9SToby Isaac   if (sections) PetscAssertPointer(sections, 5);
31349566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
31359566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
31369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
31379566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
31389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
3139af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3140af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
31419566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
31429566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3143af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
31449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3145af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
31469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
31479566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3148af9eab45SVaclav Hapla       } else {
31499566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3150af9eab45SVaclav Hapla       }
3151af9eab45SVaclav Hapla     }
31529566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
31539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
31549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
3155af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
31569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
31579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3158af9eab45SVaclav Hapla       if (cn > 1) {
31599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
31609566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3161af9eab45SVaclav Hapla       } else {
3162af9eab45SVaclav Hapla         newarr[co] = arr[i];
3163af9eab45SVaclav Hapla       }
3164af9eab45SVaclav Hapla     }
31659566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3166af9eab45SVaclav Hapla     arr = newarr;
3167af9eab45SVaclav Hapla     n   = newn;
3168af9eab45SVaclav Hapla   }
31699566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
3170af9eab45SVaclav Hapla   *depth = depth_;
3171af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
3172af9eab45SVaclav Hapla   else {
31739566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
31749566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
3175af9eab45SVaclav Hapla   }
3176af9eab45SVaclav Hapla   if (sections) *sections = sections_;
3177af9eab45SVaclav Hapla   else {
31789566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
31799566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
3180af9eab45SVaclav Hapla   }
31813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3182af9eab45SVaclav Hapla }
3183af9eab45SVaclav Hapla 
3184af9eab45SVaclav Hapla /*@
3185a1cb98faSBarry Smith   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3186af9eab45SVaclav Hapla 
3187a1cb98faSBarry Smith   Not Collective
3188af9eab45SVaclav Hapla 
3189af9eab45SVaclav Hapla   Input Parameters:
3190a1cb98faSBarry Smith + dm     - The `DMPLEX`
3191a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3192af9eab45SVaclav Hapla 
3193d8d19677SJose E. Roman   Output Parameters:
3194a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3195af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3196af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3197af9eab45SVaclav Hapla 
3198af9eab45SVaclav Hapla   Level: advanced
3199af9eab45SVaclav Hapla 
3200a1cb98faSBarry Smith   Note:
3201a1cb98faSBarry Smith   See `DMPlexGetConeRecursive()`
3202af9eab45SVaclav Hapla 
32031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3204a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`, `PetscSection`
3205af9eab45SVaclav Hapla @*/
3206d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3207d71ae5a4SJacob Faibussowitsch {
3208af9eab45SVaclav Hapla   PetscInt d, depth_;
3209af9eab45SVaclav Hapla 
3210af9eab45SVaclav Hapla   PetscFunctionBegin;
32119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
32121dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3213af9eab45SVaclav Hapla   if (depth) *depth = 0;
3214af9eab45SVaclav Hapla   if (expandedPoints) {
32159566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
32169566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3217af9eab45SVaclav Hapla   }
3218af9eab45SVaclav Hapla   if (sections) {
32199566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
32209566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3221af9eab45SVaclav Hapla   }
32223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3223d4636a37SVaclav Hapla }
3224d4636a37SVaclav Hapla 
3225552f7358SJed Brown /*@
322692371b87SBarry 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
3227552f7358SJed Brown 
3228a1cb98faSBarry Smith   Not Collective
3229552f7358SJed Brown 
3230552f7358SJed Brown   Input Parameters:
323160225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3232a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
323320f4b53cSBarry Smith - cone - An array of points which are on the in-edges for point `p`
3234552f7358SJed Brown 
3235552f7358SJed Brown   Level: beginner
3236552f7358SJed Brown 
3237a1cb98faSBarry Smith   Note:
3238a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3239a1cb98faSBarry Smith 
32401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3241552f7358SJed Brown @*/
3242d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3243d71ae5a4SJacob Faibussowitsch {
3244552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3245552f7358SJed Brown   PetscInt dof, off, c;
3246552f7358SJed Brown 
3247552f7358SJed Brown   PetscFunctionBegin;
3248552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
32504f572ea9SToby Isaac   if (dof) PetscAssertPointer(cone, 3);
32519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3252db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3253db485b19SStefano Zampini     PetscInt pStart, pEnd;
3254db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
325563a3b9bcSJacob 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);
3256552f7358SJed Brown     for (c = 0; c < dof; ++c) {
325763a3b9bcSJacob 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);
3258552f7358SJed Brown       mesh->cones[off + c] = cone[c];
3259552f7358SJed Brown     }
3260db485b19SStefano Zampini   } else {
3261db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3262db485b19SStefano Zampini   }
32633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3264552f7358SJed Brown }
3265552f7358SJed Brown 
3266552f7358SJed Brown /*@C
3267eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3268552f7358SJed Brown 
3269a1cb98faSBarry Smith   Not Collective
3270552f7358SJed Brown 
3271552f7358SJed Brown   Input Parameters:
327260225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3273a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3274552f7358SJed Brown 
3275552f7358SJed Brown   Output Parameter:
327620f4b53cSBarry Smith . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
3277b5a892a1SMatthew G. Knepley                     integer giving the prescription for cone traversal.
3278552f7358SJed Brown 
3279552f7358SJed Brown   Level: beginner
3280552f7358SJed Brown 
3281a1cb98faSBarry Smith   Note:
3282b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3283b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3284a1cb98faSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3285b5a892a1SMatthew G. Knepley   with the identity.
3286b5a892a1SMatthew G. Knepley 
328760225df5SJacob Faibussowitsch   Fortran Notes:
3288a1cb98faSBarry Smith   You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3289a1cb98faSBarry Smith   `DMPlexRestoreConeOrientation()` is not needed/available in C.
32903813dfbdSMatthew G Knepley 
32911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3292552f7358SJed Brown @*/
3293d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3294d71ae5a4SJacob Faibussowitsch {
3295552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3296552f7358SJed Brown   PetscInt off;
3297552f7358SJed Brown 
3298552f7358SJed Brown   PetscFunctionBegin;
3299552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
330076bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3301552f7358SJed Brown     PetscInt dof;
33029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
33034f572ea9SToby Isaac     if (dof) PetscAssertPointer(coneOrientation, 3);
3304552f7358SJed Brown   }
33059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
33060d644c17SKarl Rupp 
3307552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
33083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3309552f7358SJed Brown }
3310552f7358SJed Brown 
3311552f7358SJed Brown /*@
3312eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3313552f7358SJed Brown 
3314a1cb98faSBarry Smith   Not Collective
3315552f7358SJed Brown 
3316552f7358SJed Brown   Input Parameters:
331760225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3318a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3319b5a892a1SMatthew G. Knepley - coneOrientation - An array of orientations
3320b5a892a1SMatthew G. Knepley 
3321552f7358SJed Brown   Level: beginner
3322552f7358SJed Brown 
3323a1cb98faSBarry Smith   Notes:
3324a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3325a1cb98faSBarry Smith 
3326a1cb98faSBarry Smith   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3327a1cb98faSBarry Smith 
33281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3329552f7358SJed Brown @*/
3330d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3331d71ae5a4SJacob Faibussowitsch {
3332552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3333552f7358SJed Brown   PetscInt pStart, pEnd;
3334552f7358SJed Brown   PetscInt dof, off, c;
3335552f7358SJed Brown 
3336552f7358SJed Brown   PetscFunctionBegin;
3337552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
33394f572ea9SToby Isaac   if (dof) PetscAssertPointer(coneOrientation, 3);
33409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3341db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3342db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
334363a3b9bcSJacob Faibussowitsch     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3344552f7358SJed Brown     for (c = 0; c < dof; ++c) {
3345552f7358SJed Brown       PetscInt cdof, o = coneOrientation[c];
3346552f7358SJed Brown 
33479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
33481dca8a05SBarry 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);
3349552f7358SJed Brown       mesh->coneOrientations[off + c] = o;
3350552f7358SJed Brown     }
3351db485b19SStefano Zampini   } else {
3352db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3353db485b19SStefano Zampini   }
33543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3355552f7358SJed Brown }
3356552f7358SJed Brown 
33577cd05799SMatthew G. Knepley /*@
3358eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
33597cd05799SMatthew G. Knepley 
3360a1cb98faSBarry Smith   Not Collective
33617cd05799SMatthew G. Knepley 
33627cd05799SMatthew G. Knepley   Input Parameters:
336360225df5SJacob Faibussowitsch + dm        - The `DMPLEX`
3364a1cb98faSBarry Smith . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
33657cd05799SMatthew G. Knepley . conePos   - The local index in the cone where the point should be put
33667cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
33677cd05799SMatthew G. Knepley 
33687cd05799SMatthew G. Knepley   Level: beginner
33697cd05799SMatthew G. Knepley 
33701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
33717cd05799SMatthew G. Knepley @*/
3372d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3373d71ae5a4SJacob Faibussowitsch {
3374552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3375552f7358SJed Brown   PetscInt pStart, pEnd;
3376552f7358SJed Brown   PetscInt dof, off;
3377552f7358SJed Brown 
3378552f7358SJed Brown   PetscFunctionBegin;
3379552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3380a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
33819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
338263a3b9bcSJacob 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);
338363a3b9bcSJacob 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);
33849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
338563a3b9bcSJacob 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);
3386a03d55ffSStefano Zampini   }
3387a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3388552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
33893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3390552f7358SJed Brown }
3391552f7358SJed Brown 
33927cd05799SMatthew G. Knepley /*@
3393eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
33947cd05799SMatthew G. Knepley 
3395a1cb98faSBarry Smith   Not Collective
33967cd05799SMatthew G. Knepley 
33977cd05799SMatthew G. Knepley   Input Parameters:
339860225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3399a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
34007cd05799SMatthew G. Knepley . conePos         - The local index in the cone where the point should be put
34017cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
34027cd05799SMatthew G. Knepley 
34037cd05799SMatthew G. Knepley   Level: beginner
34047cd05799SMatthew G. Knepley 
3405a1cb98faSBarry Smith   Note:
3406a1cb98faSBarry Smith   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3407b5a892a1SMatthew G. Knepley 
34081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
34097cd05799SMatthew G. Knepley @*/
3410d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3411d71ae5a4SJacob Faibussowitsch {
341277c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
341377c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
341477c88f5bSMatthew G Knepley   PetscInt dof, off;
341577c88f5bSMatthew G Knepley 
341677c88f5bSMatthew G Knepley   PetscFunctionBegin;
341777c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3418a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
34199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
342063a3b9bcSJacob 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);
34219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
342263a3b9bcSJacob 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);
3423a03d55ffSStefano Zampini   }
3424a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
342577c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
34263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
342777c88f5bSMatthew G Knepley }
342877c88f5bSMatthew G Knepley 
34299f4ada15SMatthew G. Knepley /*@C
34309f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
34319f4ada15SMatthew G. Knepley 
34329f4ada15SMatthew G. Knepley   Not collective
34339f4ada15SMatthew G. Knepley 
34349f4ada15SMatthew G. Knepley   Input Parameters:
34359f4ada15SMatthew G. Knepley + dm - The DMPlex
34369f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
34379f4ada15SMatthew G. Knepley 
34389f4ada15SMatthew G. Knepley   Output Parameters:
343920f4b53cSBarry Smith + cone - An array of points which are on the in-edges for point `p`
344020f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
34419f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
34429f4ada15SMatthew G. Knepley 
34439f4ada15SMatthew G. Knepley   Level: beginner
34449f4ada15SMatthew G. Knepley 
34459f4ada15SMatthew G. Knepley   Notes:
34469f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
34479f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
344820f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
34499f4ada15SMatthew G. Knepley   with the identity.
34509f4ada15SMatthew G. Knepley 
34519f4ada15SMatthew G. Knepley   Fortran Notes:
345220f4b53cSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
345320f4b53cSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
34549f4ada15SMatthew G. Knepley 
34551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
34569f4ada15SMatthew G. Knepley @*/
34579f4ada15SMatthew G. Knepley PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
34589f4ada15SMatthew G. Knepley {
34599f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
34609f4ada15SMatthew G. Knepley 
34619f4ada15SMatthew G. Knepley   PetscFunctionBegin;
34629f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34639f4ada15SMatthew G. Knepley   if (mesh->tr) {
34649f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
34659f4ada15SMatthew G. Knepley   } else {
34669f4ada15SMatthew G. Knepley     PetscInt off;
34679f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
34689f4ada15SMatthew G. Knepley       PetscInt dof;
34699f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
34709f4ada15SMatthew G. Knepley       if (dof) {
34714f572ea9SToby Isaac         if (cone) PetscAssertPointer(cone, 3);
34724f572ea9SToby Isaac         if (ornt) PetscAssertPointer(ornt, 4);
34739f4ada15SMatthew G. Knepley       }
34749f4ada15SMatthew G. Knepley     }
34759f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3476072f5ffdSStefano Zampini     if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB
3477072f5ffdSStefano Zampini     if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL;
34789f4ada15SMatthew G. Knepley   }
34793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34809f4ada15SMatthew G. Knepley }
34819f4ada15SMatthew G. Knepley 
34829f4ada15SMatthew G. Knepley /*@C
34839f4ada15SMatthew G. Knepley   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG
34849f4ada15SMatthew G. Knepley 
348520f4b53cSBarry Smith   Not Collective
34869f4ada15SMatthew G. Knepley 
34879f4ada15SMatthew G. Knepley   Input Parameters:
34889f4ada15SMatthew G. Knepley + dm   - The DMPlex
348920f4b53cSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
34909f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
349120f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
34929f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
34939f4ada15SMatthew G. Knepley 
34949f4ada15SMatthew G. Knepley   Level: beginner
34959f4ada15SMatthew G. Knepley 
34969f4ada15SMatthew G. Knepley   Notes:
34979f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
34989f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
349920f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
35009f4ada15SMatthew G. Knepley   with the identity.
35019f4ada15SMatthew G. Knepley 
350260225df5SJacob Faibussowitsch   Fortran Notes:
350320f4b53cSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
350420f4b53cSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
35059f4ada15SMatthew G. Knepley 
35061cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
35079f4ada15SMatthew G. Knepley @*/
35089f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
35099f4ada15SMatthew G. Knepley {
35109f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
35119f4ada15SMatthew G. Knepley 
35129f4ada15SMatthew G. Knepley   PetscFunctionBegin;
35139f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35149f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
35153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35169f4ada15SMatthew G. Knepley }
35179f4ada15SMatthew G. Knepley 
3518552f7358SJed Brown /*@
3519eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3520552f7358SJed Brown 
3521a1cb98faSBarry Smith   Not Collective
3522552f7358SJed Brown 
3523552f7358SJed Brown   Input Parameters:
352460225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3525a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3526552f7358SJed Brown 
3527552f7358SJed Brown   Output Parameter:
352820f4b53cSBarry Smith . size - The support size for point `p`
3529552f7358SJed Brown 
3530552f7358SJed Brown   Level: beginner
3531552f7358SJed Brown 
35321cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3533552f7358SJed Brown @*/
3534d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3535d71ae5a4SJacob Faibussowitsch {
3536552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3537552f7358SJed Brown 
3538552f7358SJed Brown   PetscFunctionBegin;
3539552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35404f572ea9SToby Isaac   PetscAssertPointer(size, 3);
35419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
35423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3543552f7358SJed Brown }
3544552f7358SJed Brown 
3545552f7358SJed Brown /*@
3546eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3547552f7358SJed Brown 
3548a1cb98faSBarry Smith   Not Collective
3549552f7358SJed Brown 
3550552f7358SJed Brown   Input Parameters:
355160225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3552a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
355320f4b53cSBarry Smith - size - The support size for point `p`
3554552f7358SJed Brown 
3555a1cb98faSBarry Smith   Level: beginner
3556552f7358SJed Brown 
3557552f7358SJed Brown   Note:
355820f4b53cSBarry Smith   This should be called after `DMPlexSetChart()`.
3559552f7358SJed Brown 
35601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3561552f7358SJed Brown @*/
3562d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3563d71ae5a4SJacob Faibussowitsch {
3564552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3565552f7358SJed Brown 
3566552f7358SJed Brown   PetscFunctionBegin;
3567552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35689566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
35693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3570552f7358SJed Brown }
3571552f7358SJed Brown 
3572552f7358SJed Brown /*@C
3573eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3574552f7358SJed Brown 
3575a1cb98faSBarry Smith   Not Collective
3576552f7358SJed Brown 
3577552f7358SJed Brown   Input Parameters:
357860225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3579a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3580552f7358SJed Brown 
3581552f7358SJed Brown   Output Parameter:
358220f4b53cSBarry Smith . support - An array of points which are on the out-edges for point `p`
3583552f7358SJed Brown 
3584552f7358SJed Brown   Level: beginner
3585552f7358SJed Brown 
358660225df5SJacob Faibussowitsch   Fortran Notes:
3587a1cb98faSBarry Smith   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3588a1cb98faSBarry Smith   `DMPlexRestoreSupport()` is not needed/available in C.
35893813dfbdSMatthew G Knepley 
35901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3591552f7358SJed Brown @*/
3592d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3593d71ae5a4SJacob Faibussowitsch {
3594552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3595552f7358SJed Brown   PetscInt off;
3596552f7358SJed Brown 
3597552f7358SJed Brown   PetscFunctionBegin;
3598552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35994f572ea9SToby Isaac   PetscAssertPointer(support, 3);
36009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3601072f5ffdSStefano Zampini   *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB
36023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3603552f7358SJed Brown }
3604552f7358SJed Brown 
3605552f7358SJed Brown /*@
360692371b87SBarry 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
3607552f7358SJed Brown 
3608a1cb98faSBarry Smith   Not Collective
3609552f7358SJed Brown 
3610552f7358SJed Brown   Input Parameters:
361160225df5SJacob Faibussowitsch + dm      - The `DMPLEX`
3612a1cb98faSBarry Smith . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
361320f4b53cSBarry Smith - support - An array of points which are on the out-edges for point `p`
3614552f7358SJed Brown 
3615552f7358SJed Brown   Level: beginner
3616552f7358SJed Brown 
3617a1cb98faSBarry Smith   Note:
3618a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3619a1cb98faSBarry Smith 
36201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3621552f7358SJed Brown @*/
3622d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3623d71ae5a4SJacob Faibussowitsch {
3624552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3625552f7358SJed Brown   PetscInt pStart, pEnd;
3626552f7358SJed Brown   PetscInt dof, off, c;
3627552f7358SJed Brown 
3628552f7358SJed Brown   PetscFunctionBegin;
3629552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
36319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
36324f572ea9SToby Isaac   if (dof) PetscAssertPointer(support, 3);
36339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
363463a3b9bcSJacob 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);
3635552f7358SJed Brown   for (c = 0; c < dof; ++c) {
363663a3b9bcSJacob 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);
3637552f7358SJed Brown     mesh->supports[off + c] = support[c];
3638552f7358SJed Brown   }
36393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3640552f7358SJed Brown }
3641552f7358SJed Brown 
36427cd05799SMatthew G. Knepley /*@
3643eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
36447cd05799SMatthew G. Knepley 
3645a1cb98faSBarry Smith   Not Collective
36467cd05799SMatthew G. Knepley 
36477cd05799SMatthew G. Knepley   Input Parameters:
364860225df5SJacob Faibussowitsch + dm           - The `DMPLEX`
3649a1cb98faSBarry Smith . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
36507cd05799SMatthew G. Knepley . supportPos   - The local index in the cone where the point should be put
36517cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
36527cd05799SMatthew G. Knepley 
36537cd05799SMatthew G. Knepley   Level: beginner
36547cd05799SMatthew G. Knepley 
36551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
36567cd05799SMatthew G. Knepley @*/
3657d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3658d71ae5a4SJacob Faibussowitsch {
3659552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3660552f7358SJed Brown   PetscInt pStart, pEnd;
3661552f7358SJed Brown   PetscInt dof, off;
3662552f7358SJed Brown 
3663552f7358SJed Brown   PetscFunctionBegin;
3664552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
36669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
36679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
366863a3b9bcSJacob 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);
366963a3b9bcSJacob 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);
367063a3b9bcSJacob 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);
3671552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
36723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3673552f7358SJed Brown }
3674552f7358SJed Brown 
3675b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3676d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3677d71ae5a4SJacob Faibussowitsch {
3678b5a892a1SMatthew G. Knepley   switch (ct) {
3679b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3680b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3681b5a892a1SMatthew G. Knepley     break;
3682b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3683b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3684b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3685b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3686b5a892a1SMatthew G. Knepley     break;
3687b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3688b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3689b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3690b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3691b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3692b5a892a1SMatthew G. Knepley     break;
3693d71ae5a4SJacob Faibussowitsch   default:
3694d71ae5a4SJacob Faibussowitsch     return o;
3695b5a892a1SMatthew G. Knepley   }
3696b5a892a1SMatthew G. Knepley   return o;
3697b5a892a1SMatthew G. Knepley }
3698b5a892a1SMatthew G. Knepley 
3699b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3700d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3701d71ae5a4SJacob Faibussowitsch {
3702b5a892a1SMatthew G. Knepley   switch (ct) {
3703b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3704b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3705b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3706b5a892a1SMatthew G. Knepley     break;
3707b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3708b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3709b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3710b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3711b5a892a1SMatthew G. Knepley     break;
3712b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3713b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3714b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3715b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3716b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3717b5a892a1SMatthew G. Knepley     break;
3718d71ae5a4SJacob Faibussowitsch   default:
3719d71ae5a4SJacob Faibussowitsch     return o;
3720b5a892a1SMatthew G. Knepley   }
3721b5a892a1SMatthew G. Knepley   return o;
3722b5a892a1SMatthew G. Knepley }
3723b5a892a1SMatthew G. Knepley 
3724b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3725d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3726d71ae5a4SJacob Faibussowitsch {
3727b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3728b5a892a1SMatthew G. Knepley 
3729b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
37309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3731b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3732b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3733b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3734b5a892a1SMatthew G. Knepley 
37359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
37369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
37379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3738b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3739b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3740b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3741b5a892a1SMatthew G. Knepley 
37429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3743b5a892a1SMatthew G. Knepley       switch (ct) {
3744b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
37459566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
37469566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3747b5a892a1SMatthew G. Knepley         break;
3748b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
37499566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
37509566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
37519566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3752b5a892a1SMatthew G. Knepley         break;
3753b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
37549566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
37559566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
37569566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
37579566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3758b5a892a1SMatthew G. Knepley         break;
3759d71ae5a4SJacob Faibussowitsch       default:
3760d71ae5a4SJacob Faibussowitsch         break;
3761b5a892a1SMatthew G. Knepley       }
3762b5a892a1SMatthew G. Knepley     }
3763b5a892a1SMatthew G. Knepley   }
37643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3765b5a892a1SMatthew G. Knepley }
3766b5a892a1SMatthew G. Knepley 
376709015e70SStefano Zampini static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
376809015e70SStefano Zampini {
376909015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
377009015e70SStefano Zampini 
377109015e70SStefano Zampini   PetscFunctionBeginHot;
377209015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
377309015e70SStefano Zampini     if (useCone) {
377409015e70SStefano Zampini       PetscCall(DMPlexGetConeSize(dm, p, size));
377509015e70SStefano Zampini       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
377609015e70SStefano Zampini     } else {
377709015e70SStefano Zampini       PetscCall(DMPlexGetSupportSize(dm, p, size));
377809015e70SStefano Zampini       PetscCall(DMPlexGetSupport(dm, p, arr));
377909015e70SStefano Zampini     }
378009015e70SStefano Zampini   } else {
378109015e70SStefano Zampini     if (useCone) {
378209015e70SStefano Zampini       const PetscSection s   = mesh->coneSection;
378309015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
378409015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
378509015e70SStefano Zampini 
378609015e70SStefano Zampini       *size = s->atlasDof[ps];
378709015e70SStefano Zampini       *arr  = mesh->cones + off;
378809015e70SStefano Zampini       *ornt = mesh->coneOrientations + off;
378909015e70SStefano Zampini     } else {
379009015e70SStefano Zampini       const PetscSection s   = mesh->supportSection;
379109015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
379209015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
379309015e70SStefano Zampini 
379409015e70SStefano Zampini       *size = s->atlasDof[ps];
379509015e70SStefano Zampini       *arr  = mesh->supports + off;
379609015e70SStefano Zampini     }
379709015e70SStefano Zampini   }
379809015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
379909015e70SStefano Zampini }
380009015e70SStefano Zampini 
380109015e70SStefano Zampini static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
380209015e70SStefano Zampini {
380309015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
380409015e70SStefano Zampini 
380509015e70SStefano Zampini   PetscFunctionBeginHot;
380609015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
380709015e70SStefano Zampini     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
380809015e70SStefano Zampini   }
380909015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
381009015e70SStefano Zampini }
381109015e70SStefano Zampini 
3812d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3813d71ae5a4SJacob Faibussowitsch {
3814b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3815b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3816b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3817b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3818b5a892a1SMatthew G. Knepley 
3819b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3820b5a892a1SMatthew G. Knepley   if (ornt) {
38219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3822476787b7SMatthew 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;
3823b5a892a1SMatthew G. Knepley   }
3824b5a892a1SMatthew G. Knepley   if (*points) {
3825b5a892a1SMatthew G. Knepley     closure = *points;
3826b5a892a1SMatthew G. Knepley   } else {
3827b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
38289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
38299566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3830b5a892a1SMatthew G. Knepley   }
383109015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3832b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3833b5a892a1SMatthew G. Knepley     closure[off++] = p;
3834b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3835b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3836b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3837b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3838b5a892a1SMatthew G. Knepley     }
3839b5a892a1SMatthew G. Knepley   } else {
38405f80ce2aSJacob Faibussowitsch     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3841b5a892a1SMatthew G. Knepley 
3842b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3843b5a892a1SMatthew G. Knepley     closure[off++] = p;
3844b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3845b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3846b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3847b5a892a1SMatthew G. Knepley 
38489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3849b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3850b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3851b5a892a1SMatthew G. Knepley     }
3852b5a892a1SMatthew G. Knepley   }
385309015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3854b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
3855b5a892a1SMatthew G. Knepley   if (points) *points = closure;
38563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3857b5a892a1SMatthew G. Knepley }
3858b5a892a1SMatthew G. Knepley 
3859d5b43468SJose E. Roman /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3860d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3861d71ae5a4SJacob Faibussowitsch {
3862b5a892a1SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3863b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3864b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
3865b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3866b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3867b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3868b5a892a1SMatthew G. Knepley 
3869b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
38709566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
387109015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
38729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3873b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3874b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3875b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
38769371c9d4SSatish Balay   if (*points) {
38779371c9d4SSatish Balay     pts = *points;
38789371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3879b5a892a1SMatthew G. Knepley   c        = 0;
3880b5a892a1SMatthew G. Knepley   pts[c++] = point;
3881b5a892a1SMatthew G. Knepley   pts[c++] = o;
38829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
38839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
38849371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
38859371c9d4SSatish Balay     pts[c++] = closure[cl];
38869371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
38879371c9d4SSatish Balay   }
38889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
38899371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
38909371c9d4SSatish Balay     pts[c++] = closure[cl];
38919371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
38929371c9d4SSatish Balay   }
38939566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3894b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
38959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3896b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
3897b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3898b5a892a1SMatthew G. Knepley   }
389909015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3900b5a892a1SMatthew G. Knepley   if (dim >= 3) {
3901b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
3902b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3903b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
3904b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
3905b5a892a1SMatthew G. Knepley 
39069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3907b5a892a1SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
390809015e70SStefano Zampini       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3909b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
3910b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3911b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
3912b5a892a1SMatthew G. Knepley 
39139371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
39149371c9d4SSatish Balay           if (pts[i] == cp) break;
3915b5a892a1SMatthew G. Knepley         if (i == c) {
39169566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3917b5a892a1SMatthew G. Knepley           pts[c++] = cp;
3918b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3919b5a892a1SMatthew G. Knepley         }
3920b5a892a1SMatthew G. Knepley       }
392109015e70SStefano Zampini       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3922b5a892a1SMatthew G. Knepley     }
3923b5a892a1SMatthew G. Knepley   }
3924b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
3925b5a892a1SMatthew G. Knepley   *points    = pts;
39263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3927b5a892a1SMatthew G. Knepley }
3928b5a892a1SMatthew G. Knepley 
3929d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3930d71ae5a4SJacob Faibussowitsch {
3931b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
3932b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
3933b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3934b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3935b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
3936b5a892a1SMatthew G. Knepley 
3937b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
39389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
3939b5a892a1SMatthew G. Knepley   if (depth == 1) {
39409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
39413ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3942b5a892a1SMatthew G. Knepley   }
39439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
3944476787b7SMatthew 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;
3945c306944fSJed Brown   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
39469566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
39473ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3948b5a892a1SMatthew G. Knepley   }
39499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3950b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3951b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3952b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
39539566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
39549371c9d4SSatish Balay   if (*points) {
39559371c9d4SSatish Balay     closure = *points;
39569371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
3957b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
3958b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
3959b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
3960b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
3961b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
3962b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3963b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
3964b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
3965b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
3966b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
3967b5a892a1SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
396809015e70SStefano Zampini     const PetscInt      *tmp, *tmpO = NULL;
3969b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
3970b5a892a1SMatthew G. Knepley 
3971b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
3972b5a892a1SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2;
397363a3b9bcSJacob 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);
3974b5a892a1SMatthew G. Knepley     }
397509015e70SStefano Zampini     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3976b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3977b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
3978b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
3979b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
39809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
3981b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3982b5a892a1SMatthew G. Knepley       PetscInt       c;
3983b5a892a1SMatthew G. Knepley 
3984b5a892a1SMatthew G. Knepley       /* Check for duplicate */
3985b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
3986b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
3987b5a892a1SMatthew G. Knepley       }
3988b5a892a1SMatthew G. Knepley       if (c == closureSize) {
3989b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
3990b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
3991b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
3992b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
3993b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
3994b5a892a1SMatthew G. Knepley       }
3995b5a892a1SMatthew G. Knepley     }
399609015e70SStefano Zampini     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3997b5a892a1SMatthew G. Knepley   }
39989566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3999b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
4000b5a892a1SMatthew G. Knepley   if (points) *points = closure;
40013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4002b5a892a1SMatthew G. Knepley }
4003b5a892a1SMatthew G. Knepley 
4004552f7358SJed Brown /*@C
4005eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
4006552f7358SJed Brown 
4007a1cb98faSBarry Smith   Not Collective
4008552f7358SJed Brown 
4009552f7358SJed Brown   Input Parameters:
4010a1cb98faSBarry Smith + dm      - The `DMPLEX`
4011b5a892a1SMatthew G. Knepley . p       - The mesh point
4012a1cb98faSBarry Smith - useCone - `PETSC_TRUE` for the closure, otherwise return the star
4013552f7358SJed Brown 
40146b867d5aSJose E. Roman   Input/Output Parameter:
40156b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
401620f4b53cSBarry Smith            if `NULL` on input, internal storage will be returned, otherwise the provided array is used
40176b867d5aSJose E. Roman 
40186b867d5aSJose E. Roman   Output Parameter:
401920f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4020552f7358SJed Brown 
4021a1cb98faSBarry Smith   Level: beginner
4022a1cb98faSBarry Smith 
4023552f7358SJed Brown   Note:
402420f4b53cSBarry Smith   If using internal storage (points is `NULL` on input), each call overwrites the last output.
4025552f7358SJed Brown 
402660225df5SJacob Faibussowitsch   Fortran Notes:
402720f4b53cSBarry Smith   The `numPoints` argument is not present in the Fortran binding since it is internal to the array.
40283813dfbdSMatthew G Knepley 
40291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4030552f7358SJed Brown @*/
4031d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4032d71ae5a4SJacob Faibussowitsch {
4033b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4034552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40354f572ea9SToby Isaac   if (numPoints) PetscAssertPointer(numPoints, 4);
40364f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 5);
40379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
40383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40399bf0dad6SMatthew G. Knepley }
40409bf0dad6SMatthew G. Knepley 
4041552f7358SJed Brown /*@C
4042eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
4043552f7358SJed Brown 
4044a1cb98faSBarry Smith   Not Collective
4045552f7358SJed Brown 
4046552f7358SJed Brown   Input Parameters:
4047a1cb98faSBarry Smith + dm        - The `DMPLEX`
4048b5a892a1SMatthew G. Knepley . p         - The mesh point
4049a1cb98faSBarry Smith . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
405020f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4051b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
4052552f7358SJed Brown 
4053a1cb98faSBarry Smith   Level: beginner
4054a1cb98faSBarry Smith 
4055552f7358SJed Brown   Note:
405620f4b53cSBarry Smith   If not using internal storage (points is not `NULL` on input), this call is unnecessary
4057552f7358SJed Brown 
40581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4059552f7358SJed Brown @*/
4060d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4061d71ae5a4SJacob Faibussowitsch {
4062b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4063552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40644ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
40659566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
40663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4067552f7358SJed Brown }
4068552f7358SJed Brown 
4069552f7358SJed Brown /*@
4070eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
4071552f7358SJed Brown 
4072a1cb98faSBarry Smith   Not Collective
4073552f7358SJed Brown 
4074552f7358SJed Brown   Input Parameter:
407560225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4076552f7358SJed Brown 
4077552f7358SJed Brown   Output Parameters:
4078552f7358SJed Brown + maxConeSize    - The maximum number of in-edges
4079552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
4080552f7358SJed Brown 
4081552f7358SJed Brown   Level: beginner
4082552f7358SJed Brown 
40831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4084552f7358SJed Brown @*/
4085d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
4086d71ae5a4SJacob Faibussowitsch {
4087552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
4088552f7358SJed Brown 
4089552f7358SJed Brown   PetscFunctionBegin;
4090552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40911baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
40921baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
40933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4094552f7358SJed Brown }
4095552f7358SJed Brown 
4096d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
4097d71ae5a4SJacob Faibussowitsch {
4098552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
40996302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
4100552f7358SJed Brown 
4101552f7358SJed Brown   PetscFunctionBegin;
4102552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41039566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
41049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
41059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
41069566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
41076302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
41086302a7fbSVaclav Hapla   if (maxSupportSize) {
41099566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
41109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
41119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
4112552f7358SJed Brown   }
41133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4114552f7358SJed Brown }
4115552f7358SJed Brown 
4116d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4117d71ae5a4SJacob Faibussowitsch {
4118552f7358SJed Brown   PetscFunctionBegin;
41199566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
41209566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
4121ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
4122736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
412395602cf2SAlexis Marboeuf     PetscSF sfNatural;
4124f94b4a02SBlaise Bourdin 
41253dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
41269566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
412795602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4128c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
4129f94b4a02SBlaise Bourdin   }
41303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4131552f7358SJed Brown }
4132552f7358SJed Brown 
4133d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4134d71ae5a4SJacob Faibussowitsch {
41353dcd263cSBlaise Bourdin   PetscInt i = 0;
41362adcc780SMatthew G. Knepley 
41372adcc780SMatthew G. Knepley   PetscFunctionBegin;
41389566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
41399566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4140c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
41413dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
41423dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
414395602cf2SAlexis Marboeuf       PetscSF sfNatural;
41443dcd263cSBlaise Bourdin 
41453dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
41469566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4147c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
414895602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4149c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
41503dcd263cSBlaise Bourdin       break;
41513dcd263cSBlaise Bourdin     }
41523dcd263cSBlaise Bourdin   }
41533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41542adcc780SMatthew G. Knepley }
41552adcc780SMatthew G. Knepley 
4156552f7358SJed Brown /*@
4157eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4158552f7358SJed Brown 
4159a1cb98faSBarry Smith   Not Collective
4160552f7358SJed Brown 
4161552f7358SJed Brown   Input Parameter:
416260225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4163552f7358SJed Brown 
4164552f7358SJed Brown   Level: beginner
4165552f7358SJed Brown 
4166a1cb98faSBarry Smith   Note:
4167a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetCone()`
4168a1cb98faSBarry Smith 
41691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4170552f7358SJed Brown @*/
4171d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
4172d71ae5a4SJacob Faibussowitsch {
4173552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4174552f7358SJed Brown   PetscInt *offsets;
4175552f7358SJed Brown   PetscInt  supportSize;
4176552f7358SJed Brown   PetscInt  pStart, pEnd, p;
4177552f7358SJed Brown 
4178552f7358SJed Brown   PetscFunctionBegin;
4179552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
418028b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
41819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4182552f7358SJed Brown   /* Calculate support sizes */
41839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4184552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4185552f7358SJed Brown     PetscInt dof, off, c;
4186552f7358SJed Brown 
41879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
41889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
418948a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4190552f7358SJed Brown   }
41919566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
4192552f7358SJed Brown   /* Calculate supports */
41939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
41949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
41959566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4196552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4197552f7358SJed Brown     PetscInt dof, off, c;
4198552f7358SJed Brown 
41999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
42009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4201552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
4202552f7358SJed Brown       const PetscInt q = mesh->cones[c];
4203552f7358SJed Brown       PetscInt       offS;
4204552f7358SJed Brown 
42059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
42060d644c17SKarl Rupp 
4207552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
4208552f7358SJed Brown       ++offsets[q];
4209552f7358SJed Brown     }
4210552f7358SJed Brown   }
42119566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
42129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
42133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4214552f7358SJed Brown }
4215552f7358SJed Brown 
4216d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4217d71ae5a4SJacob Faibussowitsch {
4218277ea44aSLisandro Dalcin   IS stratumIS;
4219277ea44aSLisandro Dalcin 
4220277ea44aSLisandro Dalcin   PetscFunctionBegin;
42213ba16761SJacob Faibussowitsch   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
422276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4223277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4224277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
42259566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4226277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
42279566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
42289371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
42299371c9d4SSatish Balay         overlap = PETSC_TRUE;
42309371c9d4SSatish Balay         break;
42319371c9d4SSatish Balay       }
4232277ea44aSLisandro Dalcin     }
423363a3b9bcSJacob 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);
4234277ea44aSLisandro Dalcin   }
42359566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
42369566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
42379566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
42383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4239277ea44aSLisandro Dalcin }
4240277ea44aSLisandro Dalcin 
4241e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4242e91fa0a1SMatthew G. Knepley {
4243e91fa0a1SMatthew G. Knepley   PetscInt *pMin, *pMax;
4244e91fa0a1SMatthew G. Knepley   PetscInt  pStart, pEnd;
4245e91fa0a1SMatthew G. Knepley   PetscInt  dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT;
4246e91fa0a1SMatthew G. Knepley 
4247e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4248e91fa0a1SMatthew G. Knepley   {
4249e91fa0a1SMatthew G. Knepley     DMLabel label2;
4250e91fa0a1SMatthew G. Knepley 
4251e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4252e91fa0a1SMatthew G. Knepley     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4253e91fa0a1SMatthew G. Knepley   }
4254e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4255e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4256e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4257e91fa0a1SMatthew G. Knepley 
4258e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4259e91fa0a1SMatthew G. Knepley     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4260e91fa0a1SMatthew G. Knepley     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4261e91fa0a1SMatthew G. Knepley   }
4262e91fa0a1SMatthew G. Knepley   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4263e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4264e91fa0a1SMatthew G. Knepley     pMin[d] = PETSC_MAX_INT;
4265e91fa0a1SMatthew G. Knepley     pMax[d] = PETSC_MIN_INT;
4266e91fa0a1SMatthew G. Knepley   }
4267e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4268e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4269e91fa0a1SMatthew G. Knepley     PetscInt       d;
4270e91fa0a1SMatthew G. Knepley 
4271e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4272e91fa0a1SMatthew G. Knepley     d       = DMPolytopeTypeGetDim(ct);
4273e91fa0a1SMatthew G. Knepley     pMin[d] = PetscMin(p, pMin[d]);
4274e91fa0a1SMatthew G. Knepley     pMax[d] = PetscMax(p, pMax[d]);
4275e91fa0a1SMatthew G. Knepley   }
4276e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4277e91fa0a1SMatthew G. Knepley     if (pMin[d] > pMax[d]) continue;
4278e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4279e91fa0a1SMatthew G. Knepley   }
4280e91fa0a1SMatthew G. Knepley   PetscCall(PetscFree2(pMin, pMax));
4281e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4282e91fa0a1SMatthew G. Knepley }
4283e91fa0a1SMatthew G. Knepley 
4284e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4285e91fa0a1SMatthew G. Knepley {
4286e91fa0a1SMatthew G. Knepley   PetscInt pStart, pEnd;
4287e91fa0a1SMatthew G. Knepley   PetscInt numRoots = 0, numLeaves = 0;
4288e91fa0a1SMatthew G. Knepley 
4289e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4290e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4291e91fa0a1SMatthew G. Knepley   {
4292e91fa0a1SMatthew G. Knepley     /* Initialize roots and count leaves */
4293e91fa0a1SMatthew G. Knepley     PetscInt sMin = PETSC_MAX_INT;
4294e91fa0a1SMatthew G. Knepley     PetscInt sMax = PETSC_MIN_INT;
4295e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4296e91fa0a1SMatthew G. Knepley 
4297e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4298e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4299e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4300e91fa0a1SMatthew G. Knepley       if (!coneSize && supportSize) {
4301e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4302e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4303e91fa0a1SMatthew G. Knepley         ++numRoots;
4304e91fa0a1SMatthew G. Knepley       } else if (!supportSize && coneSize) {
4305e91fa0a1SMatthew G. Knepley         ++numLeaves;
4306e91fa0a1SMatthew G. Knepley       } else if (!supportSize && !coneSize) {
4307e91fa0a1SMatthew G. Knepley         /* Isolated points */
4308e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4309e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4310e91fa0a1SMatthew G. Knepley       }
4311e91fa0a1SMatthew G. Knepley     }
4312e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4313e91fa0a1SMatthew G. Knepley   }
4314e91fa0a1SMatthew G. Knepley 
4315e91fa0a1SMatthew G. Knepley   if (numRoots + numLeaves == (pEnd - pStart)) {
4316e91fa0a1SMatthew G. Knepley     PetscInt sMin = PETSC_MAX_INT;
4317e91fa0a1SMatthew G. Knepley     PetscInt sMax = PETSC_MIN_INT;
4318e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4319e91fa0a1SMatthew G. Knepley 
4320e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4321e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4322e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4323e91fa0a1SMatthew G. Knepley       if (!supportSize && coneSize) {
4324e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4325e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4326e91fa0a1SMatthew G. Knepley       }
4327e91fa0a1SMatthew G. Knepley     }
4328e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4329e91fa0a1SMatthew G. Knepley   } else {
4330e91fa0a1SMatthew G. Knepley     PetscInt level = 0;
4331e91fa0a1SMatthew G. Knepley     PetscInt qStart, qEnd;
4332e91fa0a1SMatthew G. Knepley 
4333e91fa0a1SMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4334e91fa0a1SMatthew G. Knepley     while (qEnd > qStart) {
4335e91fa0a1SMatthew G. Knepley       PetscInt sMin = PETSC_MAX_INT;
4336e91fa0a1SMatthew G. Knepley       PetscInt sMax = PETSC_MIN_INT;
4337e91fa0a1SMatthew G. Knepley 
4338e91fa0a1SMatthew G. Knepley       for (PetscInt q = qStart; q < qEnd; ++q) {
4339e91fa0a1SMatthew G. Knepley         const PetscInt *support;
4340e91fa0a1SMatthew G. Knepley         PetscInt        supportSize;
4341e91fa0a1SMatthew G. Knepley 
4342e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4343e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, q, &support));
4344e91fa0a1SMatthew G. Knepley         for (PetscInt s = 0; s < supportSize; ++s) {
4345e91fa0a1SMatthew G. Knepley           sMin = PetscMin(support[s], sMin);
4346e91fa0a1SMatthew G. Knepley           sMax = PetscMax(support[s], sMax);
4347e91fa0a1SMatthew G. Knepley         }
4348e91fa0a1SMatthew G. Knepley       }
4349e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetNumValues(label, &level));
4350e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4351e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4352e91fa0a1SMatthew G. Knepley     }
4353e91fa0a1SMatthew G. Knepley   }
4354e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4355e91fa0a1SMatthew G. Knepley }
4356e91fa0a1SMatthew G. Knepley 
4357552f7358SJed Brown /*@
4358a4e35b19SJacob Faibussowitsch   DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4359552f7358SJed Brown 
436020f4b53cSBarry Smith   Collective
4361552f7358SJed Brown 
4362552f7358SJed Brown   Input Parameter:
436360225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4364552f7358SJed Brown 
4365a1cb98faSBarry Smith   Level: beginner
4366552f7358SJed Brown 
4367552f7358SJed Brown   Notes:
4368a4e35b19SJacob Faibussowitsch   The strata group all points of the same grade, and this function calculates the strata. This
4369a4e35b19SJacob Faibussowitsch   grade can be seen as the height (or depth) of the point in the DAG.
4370a4e35b19SJacob Faibussowitsch 
4371a4e35b19SJacob Faibussowitsch   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4372a4e35b19SJacob Faibussowitsch   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4373a1cb98faSBarry Smith   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4374b1bb481bSMatthew 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
4375a1cb98faSBarry Smith   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4376a1cb98faSBarry Smith   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4377a1cb98faSBarry Smith   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4378552f7358SJed Brown 
4379b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4380b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4381b1bb481bSMatthew 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
4382b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4383a1cb98faSBarry Smith .vb
4384a1cb98faSBarry Smith   cone(c0) = {e0, v2}
4385a1cb98faSBarry Smith   cone(e0) = {v0, v1}
4386a1cb98faSBarry Smith .ve
4387a1cb98faSBarry Smith   If `DMPlexStratify()` is run on this mesh, it will give depths
4388a1cb98faSBarry Smith .vb
4389a1cb98faSBarry Smith    depth 0 = {v0, v1, v2}
4390a1cb98faSBarry Smith    depth 1 = {e0, c0}
4391a1cb98faSBarry Smith .ve
4392b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4393b1bb481bSMatthew Knepley 
4394a1cb98faSBarry Smith   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4395552f7358SJed Brown 
43961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4397552f7358SJed Brown @*/
4398d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4399d71ae5a4SJacob Faibussowitsch {
4400df0420ecSMatthew G. Knepley   DM_Plex  *mesh = (DM_Plex *)dm->data;
4401aa50250dSMatthew G. Knepley   DMLabel   label;
4402e91fa0a1SMatthew G. Knepley   PetscBool flg = PETSC_FALSE;
4403552f7358SJed Brown 
4404552f7358SJed Brown   PetscFunctionBegin;
4405552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
44069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4407277ea44aSLisandro Dalcin 
4408e91fa0a1SMatthew G. Knepley   // Create depth label
44099566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
44109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4411277ea44aSLisandro Dalcin 
4412e91fa0a1SMatthew G. Knepley   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4413e91fa0a1SMatthew G. Knepley   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4414e91fa0a1SMatthew G. Knepley   else PetscCall(DMPlexStratify_Topological_Private(dm, label));
4415552f7358SJed Brown 
4416bf4602e4SToby Isaac   { /* just in case there is an empty process */
4417bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4418bf4602e4SToby Isaac 
44199566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
4420712fec58SPierre Jolivet     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
442148a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4422bf4602e4SToby Isaac   }
44239566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
44249566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
44253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4426552f7358SJed Brown }
4427552f7358SJed Brown 
4428d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4429d71ae5a4SJacob Faibussowitsch {
4430412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4431412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4432ba2698f1SMatthew G. Knepley 
4433412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
44349566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
44359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
44369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4437ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4438ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4439ba2698f1SMatthew G. Knepley     switch (pdepth) {
4440d71ae5a4SJacob Faibussowitsch     case 0:
4441d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4442d71ae5a4SJacob Faibussowitsch       break;
4443ba2698f1SMatthew G. Knepley     case 1:
4444ba2698f1SMatthew G. Knepley       switch (coneSize) {
4445d71ae5a4SJacob Faibussowitsch       case 2:
4446d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4447d71ae5a4SJacob Faibussowitsch         break;
4448d71ae5a4SJacob Faibussowitsch       case 3:
4449d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4450d71ae5a4SJacob Faibussowitsch         break;
4451ba2698f1SMatthew G. Knepley       case 4:
4452ba2698f1SMatthew G. Knepley         switch (dim) {
4453d71ae5a4SJacob Faibussowitsch         case 2:
4454d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4455d71ae5a4SJacob Faibussowitsch           break;
4456d71ae5a4SJacob Faibussowitsch         case 3:
4457d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4458d71ae5a4SJacob Faibussowitsch           break;
4459d71ae5a4SJacob Faibussowitsch         default:
4460d71ae5a4SJacob Faibussowitsch           break;
4461ba2698f1SMatthew G. Knepley         }
4462ba2698f1SMatthew G. Knepley         break;
4463d71ae5a4SJacob Faibussowitsch       case 5:
4464d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4465d71ae5a4SJacob Faibussowitsch         break;
4466d71ae5a4SJacob Faibussowitsch       case 6:
4467d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4468d71ae5a4SJacob Faibussowitsch         break;
4469d71ae5a4SJacob Faibussowitsch       case 8:
4470d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4471d71ae5a4SJacob Faibussowitsch         break;
4472d71ae5a4SJacob Faibussowitsch       default:
4473d71ae5a4SJacob Faibussowitsch         break;
4474ba2698f1SMatthew G. Knepley       }
4475ba2698f1SMatthew G. Knepley     }
4476ba2698f1SMatthew G. Knepley   } else {
4477ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4478ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4479ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4480ba2698f1SMatthew G. Knepley       switch (dim) {
4481ba2698f1SMatthew G. Knepley       case 1:
4482ba2698f1SMatthew G. Knepley         switch (coneSize) {
4483d71ae5a4SJacob Faibussowitsch         case 2:
4484d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4485d71ae5a4SJacob Faibussowitsch           break;
4486d71ae5a4SJacob Faibussowitsch         default:
4487d71ae5a4SJacob Faibussowitsch           break;
4488ba2698f1SMatthew G. Knepley         }
4489ba2698f1SMatthew G. Knepley         break;
4490ba2698f1SMatthew G. Knepley       case 2:
4491ba2698f1SMatthew G. Knepley         switch (coneSize) {
4492d71ae5a4SJacob Faibussowitsch         case 3:
4493d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4494d71ae5a4SJacob Faibussowitsch           break;
4495d71ae5a4SJacob Faibussowitsch         case 4:
4496d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4497d71ae5a4SJacob Faibussowitsch           break;
4498d71ae5a4SJacob Faibussowitsch         default:
4499d71ae5a4SJacob Faibussowitsch           break;
4500ba2698f1SMatthew G. Knepley         }
4501ba2698f1SMatthew G. Knepley         break;
4502ba2698f1SMatthew G. Knepley       case 3:
4503ba2698f1SMatthew G. Knepley         switch (coneSize) {
4504d71ae5a4SJacob Faibussowitsch         case 4:
4505d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4506d71ae5a4SJacob Faibussowitsch           break;
45079371c9d4SSatish Balay         case 5: {
4508da9060c4SMatthew G. Knepley           const PetscInt *cone;
4509da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4510da9060c4SMatthew G. Knepley 
45119566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
45129566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4513da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4514d71ae5a4SJacob Faibussowitsch           case 3:
4515d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4516d71ae5a4SJacob Faibussowitsch             break;
4517d71ae5a4SJacob Faibussowitsch           case 4:
4518d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4519d71ae5a4SJacob Faibussowitsch             break;
4520da9060c4SMatthew G. Knepley           }
45219371c9d4SSatish Balay         } break;
4522d71ae5a4SJacob Faibussowitsch         case 6:
4523d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4524d71ae5a4SJacob Faibussowitsch           break;
4525d71ae5a4SJacob Faibussowitsch         default:
4526d71ae5a4SJacob Faibussowitsch           break;
4527ba2698f1SMatthew G. Knepley         }
4528ba2698f1SMatthew G. Knepley         break;
4529d71ae5a4SJacob Faibussowitsch       default:
4530d71ae5a4SJacob Faibussowitsch         break;
4531ba2698f1SMatthew G. Knepley       }
4532ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4533ba2698f1SMatthew G. Knepley       switch (coneSize) {
4534d71ae5a4SJacob Faibussowitsch       case 2:
4535d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4536d71ae5a4SJacob Faibussowitsch         break;
4537d71ae5a4SJacob Faibussowitsch       case 3:
4538d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4539d71ae5a4SJacob Faibussowitsch         break;
4540d71ae5a4SJacob Faibussowitsch       case 4:
4541d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4542d71ae5a4SJacob Faibussowitsch         break;
4543d71ae5a4SJacob Faibussowitsch       default:
4544d71ae5a4SJacob Faibussowitsch         break;
4545ba2698f1SMatthew G. Knepley       }
4546ba2698f1SMatthew G. Knepley     }
4547ba2698f1SMatthew G. Knepley   }
4548412e9a14SMatthew G. Knepley   *pt = ct;
45493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4550ba2698f1SMatthew G. Knepley }
4551412e9a14SMatthew G. Knepley 
4552412e9a14SMatthew G. Knepley /*@
4553412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4554412e9a14SMatthew G. Knepley 
455520f4b53cSBarry Smith   Collective
4556412e9a14SMatthew G. Knepley 
4557412e9a14SMatthew G. Knepley   Input Parameter:
455860225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4559412e9a14SMatthew G. Knepley 
4560412e9a14SMatthew G. Knepley   Level: developer
4561412e9a14SMatthew G. Knepley 
4562a1cb98faSBarry Smith   Note:
4563a1cb98faSBarry Smith   This function is normally called automatically when a cell type is requested. It creates an
4564a1cb98faSBarry Smith   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4565a1cb98faSBarry Smith   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4566412e9a14SMatthew G. Knepley 
4567a1cb98faSBarry Smith   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4568a1cb98faSBarry Smith 
45691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4570412e9a14SMatthew G. Knepley @*/
4571d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4572d71ae5a4SJacob Faibussowitsch {
4573412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4574412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4575412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4576412e9a14SMatthew G. Knepley 
4577412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4578412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4579412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
45809566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
45819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
45829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
458321027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
458421027e53SStefano Zampini   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4585412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4586327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4587412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4588412e9a14SMatthew G. Knepley 
45899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
45909566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4591476787b7SMatthew 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 " is screwed up", p);
45929566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
459321027e53SStefano Zampini     mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4594412e9a14SMatthew G. Knepley   }
45959566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
45969566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
45973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4598ba2698f1SMatthew G. Knepley }
4599ba2698f1SMatthew G. Knepley 
4600552f7358SJed Brown /*@C
4601552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4602552f7358SJed Brown 
4603552f7358SJed Brown   Not Collective
4604552f7358SJed Brown 
4605552f7358SJed Brown   Input Parameters:
4606a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4607552f7358SJed Brown . numPoints - The number of input points for the join
4608552f7358SJed Brown - points    - The input points
4609552f7358SJed Brown 
4610552f7358SJed Brown   Output Parameters:
4611552f7358SJed Brown + numCoveredPoints - The number of points in the join
4612552f7358SJed Brown - coveredPoints    - The points in the join
4613552f7358SJed Brown 
4614552f7358SJed Brown   Level: intermediate
4615552f7358SJed Brown 
4616a1cb98faSBarry Smith   Note:
4617a1cb98faSBarry Smith   Currently, this is restricted to a single level join
4618552f7358SJed Brown 
461960225df5SJacob Faibussowitsch   Fortran Notes:
462020f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
46213813dfbdSMatthew G Knepley 
46221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4623552f7358SJed Brown @*/
4624d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4625d71ae5a4SJacob Faibussowitsch {
4626552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4627552f7358SJed Brown   PetscInt *join[2];
4628552f7358SJed Brown   PetscInt  joinSize, i = 0;
4629552f7358SJed Brown   PetscInt  dof, off, p, c, m;
46306302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4631552f7358SJed Brown 
4632552f7358SJed Brown   PetscFunctionBegin;
4633552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
46344f572ea9SToby Isaac   PetscAssertPointer(points, 3);
46354f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
46364f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
46376302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
46386302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
46396302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4640552f7358SJed Brown   /* Copy in support of first point */
46419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
46429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4643ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4644552f7358SJed Brown   /* Check each successive support */
4645552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4646552f7358SJed Brown     PetscInt newJoinSize = 0;
4647552f7358SJed Brown 
46489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
46499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4650552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4651552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4652552f7358SJed Brown 
4653552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4654552f7358SJed Brown         if (point == join[i][m]) {
4655552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4656552f7358SJed Brown           break;
4657552f7358SJed Brown         }
4658552f7358SJed Brown       }
4659552f7358SJed Brown     }
4660552f7358SJed Brown     joinSize = newJoinSize;
4661552f7358SJed Brown     i        = 1 - i;
4662552f7358SJed Brown   }
4663552f7358SJed Brown   *numCoveredPoints = joinSize;
4664552f7358SJed Brown   *coveredPoints    = join[i];
46656302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
46663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4667552f7358SJed Brown }
4668552f7358SJed Brown 
4669552f7358SJed Brown /*@C
4670552f7358SJed Brown   DMPlexRestoreJoin - Restore an array for the join of the set of points
4671552f7358SJed Brown 
4672552f7358SJed Brown   Not Collective
4673552f7358SJed Brown 
4674552f7358SJed Brown   Input Parameters:
4675a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4676552f7358SJed Brown . numPoints - The number of input points for the join
4677552f7358SJed Brown - points    - The input points
4678552f7358SJed Brown 
4679552f7358SJed Brown   Output Parameters:
4680552f7358SJed Brown + numCoveredPoints - The number of points in the join
4681552f7358SJed Brown - coveredPoints    - The points in the join
4682552f7358SJed Brown 
4683552f7358SJed Brown   Level: intermediate
4684552f7358SJed Brown 
468560225df5SJacob Faibussowitsch   Fortran Notes:
468620f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4687a1cb98faSBarry Smith 
46881cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4689552f7358SJed Brown @*/
4690d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4691d71ae5a4SJacob Faibussowitsch {
4692552f7358SJed Brown   PetscFunctionBegin;
4693552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
46944f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
46954f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
46964f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
46979566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4698d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
46993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4700552f7358SJed Brown }
4701552f7358SJed Brown 
4702552f7358SJed Brown /*@C
4703552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4704552f7358SJed Brown 
4705552f7358SJed Brown   Not Collective
4706552f7358SJed Brown 
4707552f7358SJed Brown   Input Parameters:
4708a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4709552f7358SJed Brown . numPoints - The number of input points for the join
4710552f7358SJed Brown - points    - The input points
4711552f7358SJed Brown 
4712552f7358SJed Brown   Output Parameters:
4713552f7358SJed Brown + numCoveredPoints - The number of points in the join
4714552f7358SJed Brown - coveredPoints    - The points in the join
4715552f7358SJed Brown 
4716552f7358SJed Brown   Level: intermediate
4717552f7358SJed Brown 
471860225df5SJacob Faibussowitsch   Fortran Notes:
471920f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4720a1cb98faSBarry Smith 
47211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4722552f7358SJed Brown @*/
4723d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4724d71ae5a4SJacob Faibussowitsch {
4725552f7358SJed Brown   PetscInt *offsets, **closures;
4726552f7358SJed Brown   PetscInt *join[2];
4727552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
472824c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4729552f7358SJed Brown 
4730552f7358SJed Brown   PetscFunctionBegin;
4731552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47324f572ea9SToby Isaac   PetscAssertPointer(points, 3);
47334f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
47344f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4735552f7358SJed Brown 
47369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
47379566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
47389566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
47396302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
474024c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
47419566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
47429566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4743552f7358SJed Brown 
4744552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4745552f7358SJed Brown     PetscInt closureSize;
4746552f7358SJed Brown 
47479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
47480d644c17SKarl Rupp 
4749552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4750552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4751552f7358SJed Brown       PetscInt pStart, pEnd, i;
4752552f7358SJed Brown 
47539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4754552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4755552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4756552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4757552f7358SJed Brown           break;
4758552f7358SJed Brown         }
4759552f7358SJed Brown       }
4760552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4761552f7358SJed Brown     }
476263a3b9bcSJacob 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);
4763552f7358SJed Brown   }
4764552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4765552f7358SJed Brown     PetscInt dof;
4766552f7358SJed Brown 
4767552f7358SJed Brown     /* Copy in support of first point */
4768552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4769ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4770552f7358SJed Brown     /* Check each successive cone */
4771552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4772552f7358SJed Brown       PetscInt newJoinSize = 0;
4773552f7358SJed Brown 
4774552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
4775552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4776552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
4777552f7358SJed Brown 
4778552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4779552f7358SJed Brown           if (point == join[i][m]) {
4780552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
4781552f7358SJed Brown             break;
4782552f7358SJed Brown           }
4783552f7358SJed Brown         }
4784552f7358SJed Brown       }
4785552f7358SJed Brown       joinSize = newJoinSize;
4786552f7358SJed Brown       i        = 1 - i;
4787552f7358SJed Brown     }
4788552f7358SJed Brown     if (joinSize) break;
4789552f7358SJed Brown   }
4790552f7358SJed Brown   *numCoveredPoints = joinSize;
4791552f7358SJed Brown   *coveredPoints    = join[i];
479248a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
47939566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
47949566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
47956302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
47963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4797552f7358SJed Brown }
4798552f7358SJed Brown 
4799552f7358SJed Brown /*@C
4800552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4801552f7358SJed Brown 
4802552f7358SJed Brown   Not Collective
4803552f7358SJed Brown 
4804552f7358SJed Brown   Input Parameters:
4805a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4806552f7358SJed Brown . numPoints - The number of input points for the meet
4807552f7358SJed Brown - points    - The input points
4808552f7358SJed Brown 
4809552f7358SJed Brown   Output Parameters:
481060225df5SJacob Faibussowitsch + numCoveringPoints - The number of points in the meet
481160225df5SJacob Faibussowitsch - coveringPoints    - The points in the meet
4812552f7358SJed Brown 
4813552f7358SJed Brown   Level: intermediate
4814552f7358SJed Brown 
4815a1cb98faSBarry Smith   Note:
4816a1cb98faSBarry Smith   Currently, this is restricted to a single level meet
4817552f7358SJed Brown 
48183813dfbdSMatthew G Knepley   Fortran Notes:
481920f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
48203813dfbdSMatthew G Knepley 
48211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4822552f7358SJed Brown @*/
4823d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4824d71ae5a4SJacob Faibussowitsch {
4825552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4826552f7358SJed Brown   PetscInt *meet[2];
4827552f7358SJed Brown   PetscInt  meetSize, i = 0;
4828552f7358SJed Brown   PetscInt  dof, off, p, c, m;
48296302a7fbSVaclav Hapla   PetscInt  maxConeSize;
4830552f7358SJed Brown 
4831552f7358SJed Brown   PetscFunctionBegin;
4832552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48334f572ea9SToby Isaac   PetscAssertPointer(points, 3);
48344f572ea9SToby Isaac   PetscAssertPointer(numCoveringPoints, 4);
48354f572ea9SToby Isaac   PetscAssertPointer(coveringPoints, 5);
48366302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
48376302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
48386302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4839552f7358SJed Brown   /* Copy in cone of first point */
48409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
48419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4842ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4843552f7358SJed Brown   /* Check each successive cone */
4844552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4845552f7358SJed Brown     PetscInt newMeetSize = 0;
4846552f7358SJed Brown 
48479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
48489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4849552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4850552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
4851552f7358SJed Brown 
4852552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
4853552f7358SJed Brown         if (point == meet[i][m]) {
4854552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
4855552f7358SJed Brown           break;
4856552f7358SJed Brown         }
4857552f7358SJed Brown       }
4858552f7358SJed Brown     }
4859552f7358SJed Brown     meetSize = newMeetSize;
4860552f7358SJed Brown     i        = 1 - i;
4861552f7358SJed Brown   }
4862552f7358SJed Brown   *numCoveringPoints = meetSize;
4863552f7358SJed Brown   *coveringPoints    = meet[i];
48646302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
48653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4866552f7358SJed Brown }
4867552f7358SJed Brown 
4868552f7358SJed Brown /*@C
4869552f7358SJed Brown   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4870552f7358SJed Brown 
4871552f7358SJed Brown   Not Collective
4872552f7358SJed Brown 
4873552f7358SJed Brown   Input Parameters:
4874a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4875552f7358SJed Brown . numPoints - The number of input points for the meet
4876552f7358SJed Brown - points    - The input points
4877552f7358SJed Brown 
4878552f7358SJed Brown   Output Parameters:
4879552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4880552f7358SJed Brown - coveredPoints    - The points in the meet
4881552f7358SJed Brown 
4882552f7358SJed Brown   Level: intermediate
4883552f7358SJed Brown 
488460225df5SJacob Faibussowitsch   Fortran Notes:
488520f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
48863813dfbdSMatthew G Knepley 
48871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4888552f7358SJed Brown @*/
4889d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4890d71ae5a4SJacob Faibussowitsch {
4891552f7358SJed Brown   PetscFunctionBegin;
4892552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48934f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
48944f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
48954f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
48969566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4897d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
48983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4899552f7358SJed Brown }
4900552f7358SJed Brown 
4901552f7358SJed Brown /*@C
4902552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
4903552f7358SJed Brown 
4904552f7358SJed Brown   Not Collective
4905552f7358SJed Brown 
4906552f7358SJed Brown   Input Parameters:
4907a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4908552f7358SJed Brown . numPoints - The number of input points for the meet
4909552f7358SJed Brown - points    - The input points
4910552f7358SJed Brown 
4911552f7358SJed Brown   Output Parameters:
4912552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4913552f7358SJed Brown - coveredPoints    - The points in the meet
4914552f7358SJed Brown 
4915552f7358SJed Brown   Level: intermediate
4916552f7358SJed Brown 
491760225df5SJacob Faibussowitsch   Fortran Notes:
491820f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
49193813dfbdSMatthew G Knepley 
49201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4921552f7358SJed Brown @*/
4922d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4923d71ae5a4SJacob Faibussowitsch {
4924552f7358SJed Brown   PetscInt *offsets, **closures;
4925552f7358SJed Brown   PetscInt *meet[2];
4926552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
492724c766afSToby Isaac   PetscInt  p, h, c, m, mc;
4928552f7358SJed Brown 
4929552f7358SJed Brown   PetscFunctionBegin;
4930552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49314f572ea9SToby Isaac   PetscAssertPointer(points, 3);
49324f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
49334f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4934552f7358SJed Brown 
49359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
49369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
49379566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
49386302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
493924c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
49409566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
49419566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4942552f7358SJed Brown 
4943552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4944552f7358SJed Brown     PetscInt closureSize;
4945552f7358SJed Brown 
49469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
49470d644c17SKarl Rupp 
4948552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
4949552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
4950552f7358SJed Brown       PetscInt pStart, pEnd, i;
4951552f7358SJed Brown 
49529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4953552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
4954552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4955552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
4956552f7358SJed Brown           break;
4957552f7358SJed Brown         }
4958552f7358SJed Brown       }
4959552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
4960552f7358SJed Brown     }
496163a3b9bcSJacob 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);
4962552f7358SJed Brown   }
4963552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
4964552f7358SJed Brown     PetscInt dof;
4965552f7358SJed Brown 
4966552f7358SJed Brown     /* Copy in cone of first point */
4967552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
4968ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
4969552f7358SJed Brown     /* Check each successive cone */
4970552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
4971552f7358SJed Brown       PetscInt newMeetSize = 0;
4972552f7358SJed Brown 
4973552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
4974552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4975552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
4976552f7358SJed Brown 
4977552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
4978552f7358SJed Brown           if (point == meet[i][m]) {
4979552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
4980552f7358SJed Brown             break;
4981552f7358SJed Brown           }
4982552f7358SJed Brown         }
4983552f7358SJed Brown       }
4984552f7358SJed Brown       meetSize = newMeetSize;
4985552f7358SJed Brown       i        = 1 - i;
4986552f7358SJed Brown     }
4987552f7358SJed Brown     if (meetSize) break;
4988552f7358SJed Brown   }
4989552f7358SJed Brown   *numCoveredPoints = meetSize;
4990552f7358SJed Brown   *coveredPoints    = meet[i];
499148a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
49929566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
49939566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
49946302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
49953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4996552f7358SJed Brown }
4997552f7358SJed Brown 
49984e3744c5SMatthew G. Knepley /*@C
4999a1cb98faSBarry Smith   DMPlexEqual - Determine if two `DM` have the same topology
50004e3744c5SMatthew G. Knepley 
50014e3744c5SMatthew G. Knepley   Not Collective
50024e3744c5SMatthew G. Knepley 
50034e3744c5SMatthew G. Knepley   Input Parameters:
5004a1cb98faSBarry Smith + dmA - A `DMPLEX` object
5005a1cb98faSBarry Smith - dmB - A `DMPLEX` object
50064e3744c5SMatthew G. Knepley 
50072fe279fdSBarry Smith   Output Parameter:
5008a1cb98faSBarry Smith . equal - `PETSC_TRUE` if the topologies are identical
50094e3744c5SMatthew G. Knepley 
50104e3744c5SMatthew G. Knepley   Level: intermediate
50114e3744c5SMatthew G. Knepley 
5012a1cb98faSBarry Smith   Note:
50133c7db156SBarry Smith   We are not solving graph isomorphism, so we do not permute.
50144e3744c5SMatthew G. Knepley 
50151cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
50164e3744c5SMatthew G. Knepley @*/
5017d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5018d71ae5a4SJacob Faibussowitsch {
50194e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
50204e3744c5SMatthew G. Knepley 
50214e3744c5SMatthew G. Knepley   PetscFunctionBegin;
50224e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
50234e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
50244f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
50254e3744c5SMatthew G. Knepley 
50264e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
50279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
50289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
50293ba16761SJacob Faibussowitsch   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
50309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
50319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
50323ba16761SJacob Faibussowitsch   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
50334e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
50344e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
50354e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
50364e3744c5SMatthew G. Knepley 
50379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
50389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
50399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
50409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
50419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
50429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
50433ba16761SJacob Faibussowitsch     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
50444e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
50453ba16761SJacob Faibussowitsch       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
50463ba16761SJacob Faibussowitsch       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
50474e3744c5SMatthew G. Knepley     }
50489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
50499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
50509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
50519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
50523ba16761SJacob Faibussowitsch     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
50534e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
50543ba16761SJacob Faibussowitsch       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
50554e3744c5SMatthew G. Knepley     }
50564e3744c5SMatthew G. Knepley   }
50574e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
50583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50594e3744c5SMatthew G. Knepley }
50604e3744c5SMatthew G. Knepley 
50617cd05799SMatthew G. Knepley /*@C
50627cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
50637cd05799SMatthew G. Knepley 
50647cd05799SMatthew G. Knepley   Not Collective
50657cd05799SMatthew G. Knepley 
50667cd05799SMatthew G. Knepley   Input Parameters:
5067a1cb98faSBarry Smith + dm         - The `DMPLEX`
50687cd05799SMatthew G. Knepley . cellDim    - The cell dimension
50697cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
50707cd05799SMatthew G. Knepley 
50712fe279fdSBarry Smith   Output Parameter:
50727cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
50737cd05799SMatthew G. Knepley 
50747cd05799SMatthew G. Knepley   Level: developer
50757cd05799SMatthew G. Knepley 
5076a1cb98faSBarry Smith   Note:
50777cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
50787cd05799SMatthew G. Knepley 
50791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
50807cd05799SMatthew G. Knepley @*/
5081d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5082d71ae5a4SJacob Faibussowitsch {
508382f516ccSBarry Smith   MPI_Comm comm;
5084552f7358SJed Brown 
5085552f7358SJed Brown   PetscFunctionBegin;
50869566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
50874f572ea9SToby Isaac   PetscAssertPointer(numFaceVertices, 4);
5088552f7358SJed Brown   switch (cellDim) {
5089d71ae5a4SJacob Faibussowitsch   case 0:
5090d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
5091d71ae5a4SJacob Faibussowitsch     break;
5092d71ae5a4SJacob Faibussowitsch   case 1:
5093d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
5094d71ae5a4SJacob Faibussowitsch     break;
5095552f7358SJed Brown   case 2:
5096552f7358SJed Brown     switch (numCorners) {
509719436ca2SJed Brown     case 3:                 /* triangle */
509819436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5099552f7358SJed Brown       break;
510019436ca2SJed Brown     case 4:                 /* quadrilateral */
510119436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5102552f7358SJed Brown       break;
510319436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
510419436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5105552f7358SJed Brown       break;
510619436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
510719436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5108552f7358SJed Brown       break;
5109d71ae5a4SJacob Faibussowitsch     default:
5110d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5111552f7358SJed Brown     }
5112552f7358SJed Brown     break;
5113552f7358SJed Brown   case 3:
5114552f7358SJed Brown     switch (numCorners) {
511519436ca2SJed Brown     case 4:                 /* tetradehdron */
511619436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
5117552f7358SJed Brown       break;
511819436ca2SJed Brown     case 6:                 /* tet cohesive cells */
511919436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5120552f7358SJed Brown       break;
512119436ca2SJed Brown     case 8:                 /* hexahedron */
512219436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5123552f7358SJed Brown       break;
512419436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
512519436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5126552f7358SJed Brown       break;
512719436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
512819436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5129552f7358SJed Brown       break;
513019436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
513119436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5132552f7358SJed Brown       break;
513319436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
513419436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5135552f7358SJed Brown       break;
513619436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
513719436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
5138552f7358SJed Brown       break;
5139d71ae5a4SJacob Faibussowitsch     default:
5140d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5141552f7358SJed Brown     }
5142552f7358SJed Brown     break;
5143d71ae5a4SJacob Faibussowitsch   default:
5144d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5145552f7358SJed Brown   }
51463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5147552f7358SJed Brown }
5148552f7358SJed Brown 
5149552f7358SJed Brown /*@
5150a1cb98faSBarry Smith   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
5151552f7358SJed Brown 
5152552f7358SJed Brown   Not Collective
5153552f7358SJed Brown 
5154aa50250dSMatthew G. Knepley   Input Parameter:
5155a1cb98faSBarry Smith . dm - The `DMPLEX` object
5156552f7358SJed Brown 
5157aa50250dSMatthew G. Knepley   Output Parameter:
5158a1cb98faSBarry Smith . depthLabel - The `DMLabel` recording point depth
5159552f7358SJed Brown 
5160552f7358SJed Brown   Level: developer
5161552f7358SJed Brown 
51621cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5163aa50250dSMatthew G. Knepley @*/
5164d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5165d71ae5a4SJacob Faibussowitsch {
5166aa50250dSMatthew G. Knepley   PetscFunctionBegin;
5167aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51684f572ea9SToby Isaac   PetscAssertPointer(depthLabel, 2);
5169c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
51703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5171aa50250dSMatthew G. Knepley }
5172aa50250dSMatthew G. Knepley 
5173aa50250dSMatthew G. Knepley /*@
5174aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5175aa50250dSMatthew G. Knepley 
5176aa50250dSMatthew G. Knepley   Not Collective
5177aa50250dSMatthew G. Knepley 
5178aa50250dSMatthew G. Knepley   Input Parameter:
5179a1cb98faSBarry Smith . dm - The `DMPLEX` object
5180aa50250dSMatthew G. Knepley 
5181aa50250dSMatthew G. Knepley   Output Parameter:
5182aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
5183aa50250dSMatthew G. Knepley 
5184aa50250dSMatthew G. Knepley   Level: developer
5185552f7358SJed Brown 
5186b1bb481bSMatthew Knepley   Notes:
5187a1cb98faSBarry Smith   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
5188a1cb98faSBarry Smith 
5189a1cb98faSBarry Smith   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
5190a1cb98faSBarry Smith 
5191dc287ab2SVaclav Hapla   An empty mesh gives -1.
5192b1bb481bSMatthew Knepley 
51931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5194552f7358SJed Brown @*/
5195d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5196d71ae5a4SJacob Faibussowitsch {
51979f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5198aa50250dSMatthew G. Knepley   DMLabel  label;
5199aa50250dSMatthew G. Knepley   PetscInt d = 0;
5200552f7358SJed Brown 
5201552f7358SJed Brown   PetscFunctionBegin;
5202552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
52034f572ea9SToby Isaac   PetscAssertPointer(depth, 2);
52049f4ada15SMatthew G. Knepley   if (mesh->tr) {
52059f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
52069f4ada15SMatthew G. Knepley   } else {
52079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
52089566063dSJacob Faibussowitsch     if (label) PetscCall(DMLabelGetNumValues(label, &d));
5209552f7358SJed Brown     *depth = d - 1;
52109f4ada15SMatthew G. Knepley   }
52113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5212552f7358SJed Brown }
5213552f7358SJed Brown 
5214552f7358SJed Brown /*@
521520f4b53cSBarry Smith   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5216552f7358SJed Brown 
5217552f7358SJed Brown   Not Collective
5218552f7358SJed Brown 
5219552f7358SJed Brown   Input Parameters:
5220a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5221570fa34dSVaclav Hapla - depth - The requested depth
5222552f7358SJed Brown 
5223552f7358SJed Brown   Output Parameters:
522420f4b53cSBarry Smith + start - The first point at this `depth`
522520f4b53cSBarry Smith - end   - One beyond the last point at this `depth`
5226552f7358SJed Brown 
5227552f7358SJed Brown   Level: developer
5228552f7358SJed Brown 
5229a1cb98faSBarry Smith   Notes:
5230a1cb98faSBarry Smith   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5231a1cb98faSBarry Smith   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5232a1cb98faSBarry Smith   higher dimension, e.g., "edges".
5233a1cb98faSBarry Smith 
52342827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5235552f7358SJed Brown @*/
5236d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5237d71ae5a4SJacob Faibussowitsch {
52389f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5239aa50250dSMatthew G. Knepley   DMLabel  label;
524063d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
5241552f7358SJed Brown 
5242552f7358SJed Brown   PetscFunctionBegin;
5243552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
52449371c9d4SSatish Balay   if (start) {
52454f572ea9SToby Isaac     PetscAssertPointer(start, 3);
52469371c9d4SSatish Balay     *start = 0;
52479371c9d4SSatish Balay   }
52489371c9d4SSatish Balay   if (end) {
52494f572ea9SToby Isaac     PetscAssertPointer(end, 4);
52509371c9d4SSatish Balay     *end = 0;
52519371c9d4SSatish Balay   }
52529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
52533ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5254570fa34dSVaclav Hapla   if (depth < 0) {
525563d1a920SMatthew G. Knepley     if (start) *start = pStart;
525663d1a920SMatthew G. Knepley     if (end) *end = pEnd;
52573ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5258552f7358SJed Brown   }
52599f4ada15SMatthew G. Knepley   if (mesh->tr) {
52609f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
52619f4ada15SMatthew G. Knepley   } else {
52629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
526328b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5264570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
52659f4ada15SMatthew G. Knepley   }
52663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5267552f7358SJed Brown }
5268552f7358SJed Brown 
5269552f7358SJed Brown /*@
527020f4b53cSBarry Smith   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5271552f7358SJed Brown 
5272552f7358SJed Brown   Not Collective
5273552f7358SJed Brown 
5274552f7358SJed Brown   Input Parameters:
5275a1cb98faSBarry Smith + dm     - The `DMPLEX` object
5276570fa34dSVaclav Hapla - height - The requested height
5277552f7358SJed Brown 
5278552f7358SJed Brown   Output Parameters:
527920f4b53cSBarry Smith + start - The first point at this `height`
528020f4b53cSBarry Smith - end   - One beyond the last point at this `height`
5281552f7358SJed Brown 
5282552f7358SJed Brown   Level: developer
5283552f7358SJed Brown 
5284a1cb98faSBarry Smith   Notes:
5285a1cb98faSBarry Smith   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5286a1cb98faSBarry Smith   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5287a1cb98faSBarry Smith   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5288a1cb98faSBarry Smith 
52892827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5290552f7358SJed Brown @*/
5291d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5292d71ae5a4SJacob Faibussowitsch {
5293aa50250dSMatthew G. Knepley   DMLabel  label;
529463d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5295552f7358SJed Brown 
5296552f7358SJed Brown   PetscFunctionBegin;
5297552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
52989371c9d4SSatish Balay   if (start) {
52994f572ea9SToby Isaac     PetscAssertPointer(start, 3);
53009371c9d4SSatish Balay     *start = 0;
53019371c9d4SSatish Balay   }
53029371c9d4SSatish Balay   if (end) {
53034f572ea9SToby Isaac     PetscAssertPointer(end, 4);
53049371c9d4SSatish Balay     *end = 0;
53059371c9d4SSatish Balay   }
53069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
53073ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5308570fa34dSVaclav Hapla   if (height < 0) {
530963d1a920SMatthew G. Knepley     if (start) *start = pStart;
531063d1a920SMatthew G. Knepley     if (end) *end = pEnd;
53113ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5312552f7358SJed Brown   }
53139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
531459e4dc13SStefano Zampini   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
531559e4dc13SStefano Zampini   else PetscCall(DMGetDimension(dm, &depth));
531659e4dc13SStefano Zampini   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
531759e4dc13SStefano Zampini   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
53183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5319552f7358SJed Brown }
5320552f7358SJed Brown 
5321ba2698f1SMatthew G. Knepley /*@
532220f4b53cSBarry Smith   DMPlexGetPointDepth - Get the `depth` of a given point
5323ba2698f1SMatthew G. Knepley 
5324ba2698f1SMatthew G. Knepley   Not Collective
5325ba2698f1SMatthew G. Knepley 
5326d8d19677SJose E. Roman   Input Parameters:
5327a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5328ba2698f1SMatthew G. Knepley - point - The point
5329ba2698f1SMatthew G. Knepley 
5330ba2698f1SMatthew G. Knepley   Output Parameter:
533120f4b53cSBarry Smith . depth - The depth of the `point`
5332ba2698f1SMatthew G. Knepley 
5333ba2698f1SMatthew G. Knepley   Level: intermediate
5334ba2698f1SMatthew G. Knepley 
53351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5336ba2698f1SMatthew G. Knepley @*/
5337d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5338d71ae5a4SJacob Faibussowitsch {
5339ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5340ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53414f572ea9SToby Isaac   PetscAssertPointer(depth, 3);
53429566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
53433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5344ba2698f1SMatthew G. Knepley }
5345ba2698f1SMatthew G. Knepley 
5346ba2698f1SMatthew G. Knepley /*@
534720f4b53cSBarry Smith   DMPlexGetPointHeight - Get the `height` of a given point
53480c0a32dcSVaclav Hapla 
53490c0a32dcSVaclav Hapla   Not Collective
53500c0a32dcSVaclav Hapla 
5351d8d19677SJose E. Roman   Input Parameters:
5352a1cb98faSBarry Smith + dm    - The `DMPLEX` object
53530c0a32dcSVaclav Hapla - point - The point
53540c0a32dcSVaclav Hapla 
53550c0a32dcSVaclav Hapla   Output Parameter:
535620f4b53cSBarry Smith . height - The height of the `point`
53570c0a32dcSVaclav Hapla 
53580c0a32dcSVaclav Hapla   Level: intermediate
53590c0a32dcSVaclav Hapla 
53601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
53610c0a32dcSVaclav Hapla @*/
5362d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5363d71ae5a4SJacob Faibussowitsch {
53640c0a32dcSVaclav Hapla   PetscInt n, pDepth;
53650c0a32dcSVaclav Hapla 
53660c0a32dcSVaclav Hapla   PetscFunctionBegin;
53670c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53684f572ea9SToby Isaac   PetscAssertPointer(height, 3);
53699566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
53709566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
53710c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
53723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
53730c0a32dcSVaclav Hapla }
53740c0a32dcSVaclav Hapla 
53750c0a32dcSVaclav Hapla /*@
5376a1cb98faSBarry Smith   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5377ba2698f1SMatthew G. Knepley 
5378ba2698f1SMatthew G. Knepley   Not Collective
5379ba2698f1SMatthew G. Knepley 
5380ba2698f1SMatthew G. Knepley   Input Parameter:
5381a1cb98faSBarry Smith . dm - The `DMPLEX` object
5382ba2698f1SMatthew G. Knepley 
5383ba2698f1SMatthew G. Knepley   Output Parameter:
5384a1cb98faSBarry Smith . celltypeLabel - The `DMLabel` recording cell polytope type
5385412e9a14SMatthew G. Knepley 
5386ba2698f1SMatthew G. Knepley   Level: developer
5387ba2698f1SMatthew G. Knepley 
5388a1cb98faSBarry Smith   Note:
5389a1cb98faSBarry Smith   This function will trigger automatica computation of cell types. This can be disabled by calling
5390a1cb98faSBarry Smith   `DMCreateLabel`(dm, "celltype") beforehand.
5391a1cb98faSBarry Smith 
53921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5393ba2698f1SMatthew G. Knepley @*/
5394d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5395d71ae5a4SJacob Faibussowitsch {
5396ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5397ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53984f572ea9SToby Isaac   PetscAssertPointer(celltypeLabel, 2);
53999566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5400ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
54013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5402ba2698f1SMatthew G. Knepley }
5403ba2698f1SMatthew G. Knepley 
5404ba2698f1SMatthew G. Knepley /*@
5405ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5406ba2698f1SMatthew G. Knepley 
5407ba2698f1SMatthew G. Knepley   Not Collective
5408ba2698f1SMatthew G. Knepley 
5409d8d19677SJose E. Roman   Input Parameters:
5410a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5411ba2698f1SMatthew G. Knepley - cell - The cell
5412ba2698f1SMatthew G. Knepley 
5413ba2698f1SMatthew G. Knepley   Output Parameter:
5414ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5415ba2698f1SMatthew G. Knepley 
5416ba2698f1SMatthew G. Knepley   Level: intermediate
5417ba2698f1SMatthew G. Knepley 
54181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5419ba2698f1SMatthew G. Knepley @*/
5420d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5421d71ae5a4SJacob Faibussowitsch {
54229f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5423ba2698f1SMatthew G. Knepley   DMLabel  label;
5424ba2698f1SMatthew G. Knepley   PetscInt ct;
5425ba2698f1SMatthew G. Knepley 
5426ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5427ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54284f572ea9SToby Isaac   PetscAssertPointer(celltype, 3);
54299f4ada15SMatthew G. Knepley   if (mesh->tr) {
54309f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
54319f4ada15SMatthew G. Knepley   } else {
543221027e53SStefano Zampini     PetscInt pStart, pEnd;
543321027e53SStefano Zampini 
543421027e53SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
543521027e53SStefano Zampini     if (!mesh->cellTypes) { /* XXX remove? optimize? */
543621027e53SStefano Zampini       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
543721027e53SStefano Zampini       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
543821027e53SStefano Zampini       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
543921027e53SStefano Zampini       for (PetscInt p = pStart; p < pEnd; p++) {
544021027e53SStefano Zampini         PetscCall(DMLabelGetValue(label, p, &ct));
544121027e53SStefano Zampini         mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
544221027e53SStefano Zampini       }
544321027e53SStefano Zampini     }
544421027e53SStefano Zampini     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
544521027e53SStefano Zampini     if (PetscDefined(USE_DEBUG)) {
54469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
54479566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, cell, &ct));
544863a3b9bcSJacob Faibussowitsch       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5449936381afSPierre Jolivet       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
545021027e53SStefano Zampini     }
54519f4ada15SMatthew G. Knepley   }
54523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5453ba2698f1SMatthew G. Knepley }
5454ba2698f1SMatthew G. Knepley 
5455412e9a14SMatthew G. Knepley /*@
5456412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5457412e9a14SMatthew G. Knepley 
5458412e9a14SMatthew G. Knepley   Not Collective
5459412e9a14SMatthew G. Knepley 
5460412e9a14SMatthew G. Knepley   Input Parameters:
5461a1cb98faSBarry Smith + dm       - The `DMPLEX` object
5462412e9a14SMatthew G. Knepley . cell     - The cell
5463412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5464412e9a14SMatthew G. Knepley 
5465a1cb98faSBarry Smith   Level: advanced
5466a1cb98faSBarry Smith 
5467a1cb98faSBarry Smith   Note:
5468a1cb98faSBarry Smith   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5469412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5470412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5471db485b19SStefano Zampini   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5472412e9a14SMatthew G. Knepley 
54731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5474412e9a14SMatthew G. Knepley @*/
5475d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5476d71ae5a4SJacob Faibussowitsch {
547721027e53SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
5478412e9a14SMatthew G. Knepley   DMLabel  label;
547921027e53SStefano Zampini   PetscInt pStart, pEnd;
5480412e9a14SMatthew G. Knepley 
5481412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5482412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
548321027e53SStefano Zampini   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
54849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
54859566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
548621027e53SStefano Zampini   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
548721027e53SStefano Zampini   mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
54883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5489412e9a14SMatthew G. Knepley }
5490412e9a14SMatthew G. Knepley 
5491d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5492d71ae5a4SJacob Faibussowitsch {
5493efe440bfSMatthew G. Knepley   PetscSection section, s;
5494efe440bfSMatthew G. Knepley   Mat          m;
54953e922f36SToby Isaac   PetscInt     maxHeight;
5496dd4c3f67SMatthew G. Knepley   const char  *prefix;
5497552f7358SJed Brown 
5498552f7358SJed Brown   PetscFunctionBegin;
54999566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
5500dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5501dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5502dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
55039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
55049566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
55059566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
55069566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
55079566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
55089566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
55099566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
55109566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
55119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&s));
55129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&m));
55138f4c458bSMatthew G. Knepley 
55149566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
55159566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5516dd4c3f67SMatthew G. Knepley   (*cdm)->cloneOpts = PETSC_TRUE;
5517dd4c3f67SMatthew G. Knepley   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
55183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5519552f7358SJed Brown }
5520552f7358SJed Brown 
5521d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5522d71ae5a4SJacob Faibussowitsch {
55236858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
55246858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5525f19dbd58SToby Isaac 
5526f19dbd58SToby Isaac   PetscFunctionBegin;
5527f19dbd58SToby Isaac   *field = NULL;
55289566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
55299566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
55306858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
55316858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5532f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
55336858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
55346858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5535f19dbd58SToby Isaac   }
55363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5537f19dbd58SToby Isaac }
5538f19dbd58SToby Isaac 
55397cd05799SMatthew G. Knepley /*@C
55407cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
55417cd05799SMatthew G. Knepley 
55427cd05799SMatthew G. Knepley   Not Collective
55437cd05799SMatthew G. Knepley 
55442fe279fdSBarry Smith   Input Parameter:
5545a1cb98faSBarry Smith . dm - The `DMPLEX` object
55467cd05799SMatthew G. Knepley 
55477cd05799SMatthew G. Knepley   Output Parameter:
5548a1cb98faSBarry Smith . section - The `PetscSection` object
55497cd05799SMatthew G. Knepley 
55507cd05799SMatthew G. Knepley   Level: developer
55517cd05799SMatthew G. Knepley 
55521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
55537cd05799SMatthew G. Knepley @*/
5554d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5555d71ae5a4SJacob Faibussowitsch {
5556552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5557552f7358SJed Brown 
5558552f7358SJed Brown   PetscFunctionBegin;
5559552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5560552f7358SJed Brown   if (section) *section = mesh->coneSection;
55613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5562552f7358SJed Brown }
5563552f7358SJed Brown 
55647cd05799SMatthew G. Knepley /*@C
55657cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
55667cd05799SMatthew G. Knepley 
55677cd05799SMatthew G. Knepley   Not Collective
55687cd05799SMatthew G. Knepley 
55692fe279fdSBarry Smith   Input Parameter:
5570a1cb98faSBarry Smith . dm - The `DMPLEX` object
55717cd05799SMatthew G. Knepley 
55727cd05799SMatthew G. Knepley   Output Parameter:
5573a1cb98faSBarry Smith . section - The `PetscSection` object
55747cd05799SMatthew G. Knepley 
55757cd05799SMatthew G. Knepley   Level: developer
55767cd05799SMatthew G. Knepley 
55771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
55787cd05799SMatthew G. Knepley @*/
5579d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5580d71ae5a4SJacob Faibussowitsch {
55818cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
55828cb4d582SMatthew G. Knepley 
55838cb4d582SMatthew G. Knepley   PetscFunctionBegin;
55848cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
55858cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
55863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55878cb4d582SMatthew G. Knepley }
55888cb4d582SMatthew G. Knepley 
55897cd05799SMatthew G. Knepley /*@C
55907cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
55917cd05799SMatthew G. Knepley 
55927cd05799SMatthew G. Knepley   Not Collective
55937cd05799SMatthew G. Knepley 
55942fe279fdSBarry Smith   Input Parameter:
5595a1cb98faSBarry Smith . dm - The `DMPLEX` object
55967cd05799SMatthew G. Knepley 
55977cd05799SMatthew G. Knepley   Output Parameter:
55987cd05799SMatthew G. Knepley . cones - The cone for each point
55997cd05799SMatthew G. Knepley 
56007cd05799SMatthew G. Knepley   Level: developer
56017cd05799SMatthew G. Knepley 
56021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
56037cd05799SMatthew G. Knepley @*/
5604d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5605d71ae5a4SJacob Faibussowitsch {
5606552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5607552f7358SJed Brown 
5608552f7358SJed Brown   PetscFunctionBegin;
5609552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5610552f7358SJed Brown   if (cones) *cones = mesh->cones;
56113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5612552f7358SJed Brown }
5613552f7358SJed Brown 
56147cd05799SMatthew G. Knepley /*@C
56157cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
56167cd05799SMatthew G. Knepley 
56177cd05799SMatthew G. Knepley   Not Collective
56187cd05799SMatthew G. Knepley 
56192fe279fdSBarry Smith   Input Parameter:
5620a1cb98faSBarry Smith . dm - The `DMPLEX` object
56217cd05799SMatthew G. Knepley 
56227cd05799SMatthew G. Knepley   Output Parameter:
5623b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
56247cd05799SMatthew G. Knepley 
56257cd05799SMatthew G. Knepley   Level: developer
56267cd05799SMatthew G. Knepley 
5627b5a892a1SMatthew G. Knepley   Notes:
5628a1cb98faSBarry Smith   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`.
5629b5a892a1SMatthew G. Knepley 
5630a1cb98faSBarry Smith   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5631b5a892a1SMatthew G. Knepley 
56321cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
56337cd05799SMatthew G. Knepley @*/
5634d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5635d71ae5a4SJacob Faibussowitsch {
5636552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5637552f7358SJed Brown 
5638552f7358SJed Brown   PetscFunctionBegin;
5639552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5640552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
56413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5642552f7358SJed Brown }
5643552f7358SJed Brown 
5644552f7358SJed Brown /******************************** FEM Support **********************************/
5645552f7358SJed Brown 
5646d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5647d2b2dc1eSMatthew G. Knepley {
5648d2b2dc1eSMatthew G. Knepley   PetscInt depth;
5649d2b2dc1eSMatthew G. Knepley 
5650d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
5651d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
5652d2b2dc1eSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5653d2b2dc1eSMatthew G. Knepley   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5654d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
5655d2b2dc1eSMatthew G. Knepley }
5656d2b2dc1eSMatthew G. Knepley 
56575962854dSMatthew G. Knepley PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
56585962854dSMatthew G. Knepley {
56595962854dSMatthew G. Knepley   PetscInt depth;
56605962854dSMatthew G. Knepley 
56615962854dSMatthew G. Knepley   PetscFunctionBegin;
56625962854dSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
56635962854dSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
56645962854dSMatthew G. Knepley   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
56655962854dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
56665962854dSMatthew G. Knepley }
56675962854dSMatthew G. Knepley 
56689e8305c2SJed Brown /*
56699e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
56709e8305c2SJed Brown  representing a line in the section.
56719e8305c2SJed Brown */
5672e327e467SRezgar Shakeri static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous)
5673d71ae5a4SJacob Faibussowitsch {
5674e327e467SRezgar Shakeri   PetscObject  obj;
5675e327e467SRezgar Shakeri   PetscClassId id;
5676e327e467SRezgar Shakeri   PetscFE      fe = NULL;
5677e327e467SRezgar Shakeri 
56789e8305c2SJed Brown   PetscFunctionBeginHot;
56799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5680e327e467SRezgar Shakeri   PetscCall(DMGetField(dm, field, NULL, &obj));
5681e327e467SRezgar Shakeri   PetscCall(PetscObjectGetClassId(obj, &id));
5682e327e467SRezgar Shakeri   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;
5683e327e467SRezgar Shakeri 
5684e327e467SRezgar Shakeri   if (!fe) {
5685e327e467SRezgar Shakeri     /* Assume the full interpolated mesh is in the chart; lines in particular */
56869e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
56879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
56889e8305c2SJed Brown     *k = *k / *Nc + 1;
5689e327e467SRezgar Shakeri   } else {
5690e327e467SRezgar Shakeri     PetscInt       dual_space_size, dim;
5691e327e467SRezgar Shakeri     PetscDualSpace dual_space;
5692e327e467SRezgar Shakeri     PetscCall(DMGetDimension(dm, &dim));
5693e327e467SRezgar Shakeri     PetscCall(PetscFEGetDualSpace(fe, &dual_space));
5694e327e467SRezgar Shakeri     PetscCall(PetscDualSpaceGetDimension(dual_space, &dual_space_size));
5695e327e467SRezgar Shakeri     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
5696e327e467SRezgar Shakeri     PetscCall(PetscDualSpaceLagrangeGetContinuity(dual_space, continuous));
56979e8305c2SJed Brown   }
56983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56999e8305c2SJed Brown }
57009e8305c2SJed Brown 
5701a4355906SMatthew Knepley /*@
5702bc1eb3faSJed Brown 
5703bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5704bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
570520f4b53cSBarry Smith   section provided (or the section of the `DM`).
5706a4355906SMatthew Knepley 
5707a4355906SMatthew Knepley   Input Parameters:
570820f4b53cSBarry Smith + dm      - The `DM`
570920f4b53cSBarry Smith . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
571020f4b53cSBarry Smith - section - The `PetscSection` to reorder, or `NULL` for the default section
5711a4355906SMatthew Knepley 
5712bc1eb3faSJed Brown   Example:
5713bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5714bc1eb3faSJed Brown .vb
5715bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5716bc1eb3faSJed Brown 
5717bc1eb3faSJed Brown   v4 -- e6 -- v3
5718bc1eb3faSJed Brown   |           |
5719bc1eb3faSJed Brown   e7    c0    e8
5720bc1eb3faSJed Brown   |           |
5721bc1eb3faSJed Brown   v1 -- e5 -- v2
5722bc1eb3faSJed Brown .ve
5723bc1eb3faSJed Brown 
5724bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5725bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5726bc1eb3faSJed Brown .vb
5727bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5728bc1eb3faSJed Brown     v1 -> [4]
5729bc1eb3faSJed Brown     ...
5730bc1eb3faSJed Brown     e5 -> [8, 9]
5731bc1eb3faSJed Brown .ve
5732bc1eb3faSJed Brown 
5733bc1eb3faSJed Brown   which corresponds to the dofs
5734bc1eb3faSJed Brown .vb
5735bc1eb3faSJed Brown     6   10  11  7
5736bc1eb3faSJed Brown     13  2   3   15
5737bc1eb3faSJed Brown     12  0   1   14
5738bc1eb3faSJed Brown     4   8   9   5
5739bc1eb3faSJed Brown .ve
5740bc1eb3faSJed Brown 
5741bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5742bc1eb3faSJed Brown .vb
5743bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5744bc1eb3faSJed Brown .ve
5745bc1eb3faSJed Brown 
5746bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5747bc1eb3faSJed Brown .vb
5748bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5749bc1eb3faSJed Brown .ve
5750bc1eb3faSJed Brown 
5751a4355906SMatthew Knepley   Level: developer
5752a4355906SMatthew Knepley 
5753da9ac489SAlbert Cowie   Notes:
5754a1cb98faSBarry Smith   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5755a1cb98faSBarry Smith   degree of the basis.
5756a1cb98faSBarry Smith 
5757da9ac489SAlbert Cowie   This is required to run with libCEED.
5758da9ac489SAlbert Cowie 
57591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5760a4355906SMatthew Knepley @*/
5761d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5762d71ae5a4SJacob Faibussowitsch {
57637391a63aSMatthew G. Knepley   DMLabel   label;
5764bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
5765e327e467SRezgar Shakeri   PetscBool continuous = PETSC_TRUE;
57663194fc30SMatthew G. Knepley 
57673194fc30SMatthew G. Knepley   PetscFunctionBegin;
57689566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
57693ba16761SJacob Faibussowitsch   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5770a433471fSStefano Zampini   if (point < 0) {
5771a433471fSStefano Zampini     PetscInt sStart, sEnd;
5772a433471fSStefano Zampini 
57739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5774a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
5775a433471fSStefano Zampini   }
57769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
57779566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
57789566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
57799371c9d4SSatish Balay   if (depth == 1) {
57809371c9d4SSatish Balay     eStart = point;
57819371c9d4SSatish Balay   } else if (depth == dim) {
57827391a63aSMatthew G. Knepley     const PetscInt *cone;
57837391a63aSMatthew G. Knepley 
57849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5785d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5786d4e6627bSStefano Zampini     else if (dim == 3) {
5787d4e6627bSStefano Zampini       const PetscInt *cone2;
57889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5789d4e6627bSStefano Zampini       eStart = cone2[0];
579063a3b9bcSJacob 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);
579163a3b9bcSJacob 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);
5792e327e467SRezgar Shakeri 
57939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5794bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
5795bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5796bb197d40SJed Brown     PetscInt *perm;
5797bb197d40SJed Brown 
57983194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5799e327e467SRezgar Shakeri       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous));
5800bb197d40SJed Brown       size += PetscPowInt(k + 1, d) * Nc;
58013194fc30SMatthew G. Knepley     }
58029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
58033194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5804bb197d40SJed Brown       switch (d) {
5805babf31e0SJed Brown       case 1:
5806e327e467SRezgar Shakeri         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous));
5807babf31e0SJed Brown         /*
5808babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5809babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5810babf31e0SJed Brown          */
5811e327e467SRezgar Shakeri         if (continuous) {
5812babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
58139371c9d4SSatish Balay           for (i = 0; i < k - 1; i++)
58149371c9d4SSatish Balay             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5815babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5816babf31e0SJed Brown           foffset = offset;
5817e327e467SRezgar Shakeri         } else {
5818e327e467SRezgar Shakeri           for (i = offset; i < size; i++) perm[i] = i - offset + foffset;
5819e327e467SRezgar Shakeri           foffset = offset = size;
5820e327e467SRezgar Shakeri         }
5821babf31e0SJed Brown         break;
582289eabcffSMatthew G. Knepley       case 2:
58233194fc30SMatthew 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} */
5824e327e467SRezgar Shakeri         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous));
58253194fc30SMatthew G. Knepley         /* The SEM order is
58263194fc30SMatthew G. Knepley 
58273194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
582889eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
58293194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
58303194fc30SMatthew G. Knepley          */
5831e327e467SRezgar Shakeri         if (continuous) {
58323194fc30SMatthew G. Knepley           const PetscInt of   = 0;
58333194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
58343194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
58353194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
58363194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
58373194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
58383194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
58393194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
58403194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
58413194fc30SMatthew G. Knepley           PetscInt       o;
58423194fc30SMatthew G. Knepley 
58433194fc30SMatthew G. Knepley           /* bottom */
58443194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
58459371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
58469371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
58473194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
58483194fc30SMatthew G. Knepley           /* middle */
58493194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
58503194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
58519371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
58529371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
58533194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
58543194fc30SMatthew G. Knepley           }
58553194fc30SMatthew G. Knepley           /* top */
58563194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
58579371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
58589371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
58593194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
58603194fc30SMatthew G. Knepley           foffset = offset;
5861e327e467SRezgar Shakeri         } else {
5862e327e467SRezgar Shakeri           for (i = offset; i < size; i++) perm[i] = i - offset + foffset;
5863e327e467SRezgar Shakeri           foffset = offset = size;
58643194fc30SMatthew G. Knepley         }
586589eabcffSMatthew G. Knepley         break;
586689eabcffSMatthew G. Knepley       case 3:
586789eabcffSMatthew G. Knepley         /* The original hex closure is
586889eabcffSMatthew G. Knepley 
586989eabcffSMatthew G. Knepley          {c,
587089eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
587189eabcffSMatthew 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,
587289eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
587389eabcffSMatthew G. Knepley          */
5874e327e467SRezgar Shakeri         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous));
587589eabcffSMatthew G. Knepley         /* The SEM order is
587689eabcffSMatthew G. Knepley          Bottom Slice
587789eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
587889eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
587989eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
588089eabcffSMatthew G. Knepley 
588189eabcffSMatthew G. Knepley          Middle Slice (j)
588289eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
588389eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
588489eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
588589eabcffSMatthew G. Knepley 
588689eabcffSMatthew G. Knepley          Top Slice
588789eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
588889eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
588989eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
589089eabcffSMatthew G. Knepley          */
5891e327e467SRezgar Shakeri         if (continuous) {
589289eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
589389eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
589489eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
589589eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
589689eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
589789eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
589889eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
589989eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
590089eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
590189eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
590289eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
590389eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
590489eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
590589eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
590689eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
590789eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
590889eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
590989eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
591089eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
591189eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
591289eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
591389eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
591489eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
591589eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
591689eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
591789eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
591889eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
591989eabcffSMatthew G. Knepley           PetscInt       o, n;
592089eabcffSMatthew G. Knepley 
592189eabcffSMatthew G. Knepley           /* Bottom Slice */
592289eabcffSMatthew G. Knepley           /*   bottom */
592389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
59249371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
59259371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
592689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
592789eabcffSMatthew G. Knepley           /*   middle */
592889eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
592989eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
59309371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
59319371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
59329371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
59339371c9d4SSatish Balay             }
593489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
59353194fc30SMatthew G. Knepley           }
593689eabcffSMatthew G. Knepley           /*   top */
593789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
59389371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
59399371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
594089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
594189eabcffSMatthew G. Knepley 
594289eabcffSMatthew G. Knepley           /* Middle Slice */
594389eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
594489eabcffSMatthew G. Knepley             /*   bottom */
594589eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
59469371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
59479371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
594889eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
594989eabcffSMatthew G. Knepley             /*   middle */
595089eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
595189eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
59529371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
59539371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
595489eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
595589eabcffSMatthew G. Knepley             }
595689eabcffSMatthew G. Knepley             /*   top */
595789eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
59589371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
59599371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
596089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
596189eabcffSMatthew G. Knepley           }
596289eabcffSMatthew G. Knepley 
596389eabcffSMatthew G. Knepley           /* Top Slice */
596489eabcffSMatthew G. Knepley           /*   bottom */
596589eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
59669371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
59679371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
596889eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
596989eabcffSMatthew G. Knepley           /*   middle */
597089eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
597189eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
59729371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
59739371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
597489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
597589eabcffSMatthew G. Knepley           }
597689eabcffSMatthew G. Knepley           /*   top */
597789eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
59789371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
59799371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
598089eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
598189eabcffSMatthew G. Knepley 
598289eabcffSMatthew G. Knepley           foffset = offset;
5983e327e467SRezgar Shakeri         } else {
5984e327e467SRezgar Shakeri           for (i = offset; i < size; i++) perm[i] = i - offset + foffset;
5985e327e467SRezgar Shakeri           foffset = offset = size;
598689eabcffSMatthew G. Knepley         }
598789eabcffSMatthew G. Knepley         break;
5988d71ae5a4SJacob Faibussowitsch       default:
5989d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
599089eabcffSMatthew G. Knepley       }
599189eabcffSMatthew G. Knepley     }
599263a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
59933194fc30SMatthew G. Knepley     /* Check permutation */
59943194fc30SMatthew G. Knepley     {
59953194fc30SMatthew G. Knepley       PetscInt *check;
59963194fc30SMatthew G. Knepley 
59979566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
59981dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
59991dca8a05SBarry Smith         check[i] = -1;
60001dca8a05SBarry 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]);
60011dca8a05SBarry Smith       }
60023194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
60031dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
60049566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
60053194fc30SMatthew G. Knepley     }
60069566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6007a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6008a05c9aa3SJed Brown       PetscInt *loc_perm;
60099566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6010a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
6011a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
6012a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
6013a05c9aa3SJed Brown       }
60149566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6015a05c9aa3SJed Brown     }
6016bb197d40SJed Brown   }
60173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60183194fc30SMatthew G. Knepley }
60193194fc30SMatthew G. Knepley 
6020d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6021d71ae5a4SJacob Faibussowitsch {
6022e071409bSToby Isaac   PetscDS  prob;
6023e071409bSToby Isaac   PetscInt depth, Nf, h;
6024e071409bSToby Isaac   DMLabel  label;
6025e071409bSToby Isaac 
6026e071409bSToby Isaac   PetscFunctionBeginHot;
60279566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
6028e071409bSToby Isaac   Nf      = prob->Nf;
6029e071409bSToby Isaac   label   = dm->depthLabel;
6030e071409bSToby Isaac   *dspace = NULL;
6031e071409bSToby Isaac   if (field < Nf) {
6032e071409bSToby Isaac     PetscObject disc = prob->disc[field];
6033e071409bSToby Isaac 
6034e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
6035e071409bSToby Isaac       PetscDualSpace dsp;
6036e071409bSToby Isaac 
60379566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
60389566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
60399566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
6040e071409bSToby Isaac       h = depth - 1 - h;
6041e071409bSToby Isaac       if (h) {
60429566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6043e071409bSToby Isaac       } else {
6044e071409bSToby Isaac         *dspace = dsp;
6045e071409bSToby Isaac       }
6046e071409bSToby Isaac     }
6047e071409bSToby Isaac   }
60483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6049e071409bSToby Isaac }
6050e071409bSToby Isaac 
6051d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6052d71ae5a4SJacob Faibussowitsch {
605328351e22SJed Brown   PetscScalar       *array;
605428351e22SJed Brown   const PetscScalar *vArray;
6055d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
60561a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
6057552f7358SJed Brown 
60581b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
60599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
60609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
60619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
60629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
60633f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
60649df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
60659df71ca4SMatthew G. Knepley       PetscInt dof;
6066d9917b9dSMatthew G. Knepley 
60679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
60689df71ca4SMatthew G. Knepley       size += dof;
60699df71ca4SMatthew G. Knepley     }
60709df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
60719df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
60722a3aaacfSMatthew G. Knepley       PetscInt       dof;
60735a1bb5cfSMatthew G. Knepley 
60745a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
60759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
60765a1bb5cfSMatthew G. Knepley       size += dof;
60775a1bb5cfSMatthew G. Knepley     }
60783f7cbbe7SMatthew G. Knepley     if (!values) {
60793f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
60803ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
60813f7cbbe7SMatthew G. Knepley     }
60829566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6083982e9ed1SMatthew G. Knepley   } else {
6084982e9ed1SMatthew G. Knepley     array = *values;
6085982e9ed1SMatthew G. Knepley   }
60869df71ca4SMatthew G. Knepley   size = 0;
608728351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
60889df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
60899df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
609028351e22SJed Brown     const PetscScalar *varr;
6091d9917b9dSMatthew G. Knepley 
60929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
60939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
60949df71ca4SMatthew G. Knepley     varr = &vArray[off];
6095ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
60969df71ca4SMatthew G. Knepley     size += dof;
60979df71ca4SMatthew G. Knepley   }
60989df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
60999df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
61009df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
61015a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
610228351e22SJed Brown     const PetscScalar *varr;
61035a1bb5cfSMatthew G. Knepley 
610452ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
61059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
61069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
61075a1bb5cfSMatthew G. Knepley     varr = &vArray[off];
61085a1bb5cfSMatthew G. Knepley     if (o >= 0) {
6109ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
61105a1bb5cfSMatthew G. Knepley     } else {
6111ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
61125a1bb5cfSMatthew G. Knepley     }
61139df71ca4SMatthew G. Knepley     size += dof;
61145a1bb5cfSMatthew G. Knepley   }
611528351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
61169df71ca4SMatthew G. Knepley   if (!*values) {
61175a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
61185a1bb5cfSMatthew G. Knepley     *values = array;
61199df71ca4SMatthew G. Knepley   } else {
612063a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
61218c312ff3SMatthew G. Knepley     *csize = size;
61229df71ca4SMatthew G. Knepley   }
61233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61245a1bb5cfSMatthew G. Knepley }
6125d9917b9dSMatthew G. Knepley 
612627f02ce8SMatthew G. Knepley /* Compress out points not in the section */
6127d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6128d71ae5a4SJacob Faibussowitsch {
612927f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
613027f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
613127f02ce8SMatthew G. Knepley 
61329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
613327f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
613427f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
613527f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
613627f02ce8SMatthew G. Knepley       points[q * 2]     = r;
613727f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
613827f02ce8SMatthew G. Knepley       ++q;
613927f02ce8SMatthew G. Knepley     }
614027f02ce8SMatthew G. Knepley   }
614127f02ce8SMatthew G. Knepley   *numPoints = q;
61423ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
614327f02ce8SMatthew G. Knepley }
614427f02ce8SMatthew G. Knepley 
614597529cf3SJed Brown /* Compressed closure does not apply closure permutation */
614607218a29SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6147d71ae5a4SJacob Faibussowitsch {
614827f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
6149923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
6150923c78e0SToby Isaac 
6151923c78e0SToby Isaac   PetscFunctionBeginHot;
61529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
615307218a29SMatthew G. Knepley   if (!ornt && *clPoints) {
6154923c78e0SToby Isaac     PetscInt dof, off;
6155923c78e0SToby Isaac 
61569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
61579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
61589566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
6159923c78e0SToby Isaac     np  = dof / 2;
6160923c78e0SToby Isaac     pts = (PetscInt *)&cla[off];
616127f02ce8SMatthew G. Knepley   } else {
616207218a29SMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
61639566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
6164923c78e0SToby Isaac   }
6165923c78e0SToby Isaac   *numPoints = np;
6166923c78e0SToby Isaac   *points    = pts;
6167923c78e0SToby Isaac   *clp       = cla;
61683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6169923c78e0SToby Isaac }
6170923c78e0SToby Isaac 
6171d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6172d71ae5a4SJacob Faibussowitsch {
6173923c78e0SToby Isaac   PetscFunctionBeginHot;
6174923c78e0SToby Isaac   if (!*clPoints) {
61759566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6176923c78e0SToby Isaac   } else {
61779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
6178923c78e0SToby Isaac   }
6179923c78e0SToby Isaac   *numPoints = 0;
6180923c78e0SToby Isaac   *points    = NULL;
6181923c78e0SToby Isaac   *clSec     = NULL;
6182923c78e0SToby Isaac   *clPoints  = NULL;
6183923c78e0SToby Isaac   *clp       = NULL;
61843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6185923c78e0SToby Isaac }
6186923c78e0SToby Isaac 
6187d71ae5a4SJacob 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[])
6188d71ae5a4SJacob Faibussowitsch {
61891a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
619097e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
619197e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
61921a271a75SMatthew G. Knepley 
61931a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6194fe02ba77SJed Brown   *size = 0;
61959566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
619697e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
619797e99dd9SToby Isaac     const PetscInt     point = points[2 * p];
619897e99dd9SToby Isaac     const PetscInt    *perm  = perms ? perms[p] : NULL;
619997e99dd9SToby Isaac     const PetscScalar *flip  = flips ? flips[p] : NULL;
62001a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
62011a271a75SMatthew G. Knepley     const PetscScalar *varr;
62021a271a75SMatthew G. Knepley 
62039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
62049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
62051a271a75SMatthew G. Knepley     varr = &vArray[off];
620697e99dd9SToby Isaac     if (clperm) {
620797e99dd9SToby Isaac       if (perm) {
620897e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
62091a271a75SMatthew G. Knepley       } else {
621097e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
621197e99dd9SToby Isaac       }
621297e99dd9SToby Isaac       if (flip) {
621397e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
621497e99dd9SToby Isaac       }
621597e99dd9SToby Isaac     } else {
621697e99dd9SToby Isaac       if (perm) {
621797e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
621897e99dd9SToby Isaac       } else {
621997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
622097e99dd9SToby Isaac       }
622197e99dd9SToby Isaac       if (flip) {
622297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
62231a271a75SMatthew G. Knepley       }
62241a271a75SMatthew G. Knepley     }
622597e99dd9SToby Isaac     offset += dof;
622697e99dd9SToby Isaac   }
62279566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
62281a271a75SMatthew G. Knepley   *size = offset;
62293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62301a271a75SMatthew G. Knepley }
62311a271a75SMatthew G. Knepley 
6232d71ae5a4SJacob 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[])
6233d71ae5a4SJacob Faibussowitsch {
62341a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
62351a271a75SMatthew G. Knepley 
62361a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6237fe02ba77SJed Brown   *size = 0;
62381a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
623997e99dd9SToby Isaac     PetscInt            p;
624097e99dd9SToby Isaac     const PetscInt    **perms = NULL;
624197e99dd9SToby Isaac     const PetscScalar **flips = NULL;
62421a271a75SMatthew G. Knepley 
62439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
624497e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
624597e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
624697e99dd9SToby Isaac       PetscInt           fdof, foff, b;
62471a271a75SMatthew G. Knepley       const PetscScalar *varr;
624897e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
624997e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
62501a271a75SMatthew G. Knepley 
62519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
62529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
62531a271a75SMatthew G. Knepley       varr = &vArray[foff];
625497e99dd9SToby Isaac       if (clperm) {
62559371c9d4SSatish Balay         if (perm) {
6256ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
62571a271a75SMatthew G. Knepley         } else {
6258ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
62599371c9d4SSatish Balay         }
62609371c9d4SSatish Balay         if (flip) {
6261ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
62629371c9d4SSatish Balay         }
62639371c9d4SSatish Balay       } else {
62649371c9d4SSatish Balay         if (perm) {
6265ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
62669371c9d4SSatish Balay         } else {
6267ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
62689371c9d4SSatish Balay         }
62699371c9d4SSatish Balay         if (flip) {
6270ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
62719371c9d4SSatish Balay         }
62721a271a75SMatthew G. Knepley       }
627397e99dd9SToby Isaac       offset += fdof;
62741a271a75SMatthew G. Knepley     }
62759566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
62761a271a75SMatthew G. Knepley   }
62771a271a75SMatthew G. Knepley   *size = offset;
62783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62791a271a75SMatthew G. Knepley }
62801a271a75SMatthew G. Knepley 
6281e8e188d2SZach Atkins PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
628207218a29SMatthew G. Knepley {
628307218a29SMatthew G. Knepley   PetscSection    clSection;
628407218a29SMatthew G. Knepley   IS              clPoints;
628507218a29SMatthew G. Knepley   PetscInt       *points = NULL;
6286e8e188d2SZach Atkins   const PetscInt *clp, *perm = NULL;
628707218a29SMatthew G. Knepley   PetscInt        depth, numFields, numPoints, asize;
628807218a29SMatthew G. Knepley 
628907218a29SMatthew G. Knepley   PetscFunctionBeginHot;
629007218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
629107218a29SMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
629207218a29SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6293e8e188d2SZach Atkins   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
629407218a29SMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
629507218a29SMatthew G. Knepley   PetscCall(PetscSectionGetNumFields(section, &numFields));
629607218a29SMatthew G. Knepley   if (depth == 1 && numFields < 2) {
629707218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
629807218a29SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
629907218a29SMatthew G. Knepley   }
630007218a29SMatthew G. Knepley   /* Get points */
630107218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
630207218a29SMatthew G. Knepley   /* Get sizes */
630307218a29SMatthew G. Knepley   asize = 0;
630407218a29SMatthew G. Knepley   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
630507218a29SMatthew G. Knepley     PetscInt dof;
630607218a29SMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, points[p], &dof));
630707218a29SMatthew G. Knepley     asize += dof;
630807218a29SMatthew G. Knepley   }
630907218a29SMatthew G. Knepley   if (values) {
631007218a29SMatthew G. Knepley     const PetscScalar *vArray;
631107218a29SMatthew G. Knepley     PetscInt           size;
631207218a29SMatthew G. Knepley 
631307218a29SMatthew G. Knepley     if (*values) {
631407218a29SMatthew 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);
631507218a29SMatthew G. Knepley     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6316e8e188d2SZach Atkins     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
631707218a29SMatthew G. Knepley     PetscCall(VecGetArrayRead(v, &vArray));
631807218a29SMatthew G. Knepley     /* Get values */
631907218a29SMatthew G. Knepley     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
632007218a29SMatthew G. Knepley     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
632107218a29SMatthew 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);
632207218a29SMatthew G. Knepley     /* Cleanup array */
632307218a29SMatthew G. Knepley     PetscCall(VecRestoreArrayRead(v, &vArray));
632407218a29SMatthew G. Knepley   }
632507218a29SMatthew G. Knepley   if (csize) *csize = asize;
632607218a29SMatthew G. Knepley   /* Cleanup points */
632707218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
632807218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
632907218a29SMatthew G. Knepley }
633007218a29SMatthew G. Knepley 
6331552f7358SJed Brown /*@C
6332552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6333552f7358SJed Brown 
6334552f7358SJed Brown   Not collective
6335552f7358SJed Brown 
6336552f7358SJed Brown   Input Parameters:
6337a1cb98faSBarry Smith + dm      - The `DM`
633820f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6339552f7358SJed Brown . v       - The local vector
6340a1cb98faSBarry Smith - point   - The point in the `DM`
6341552f7358SJed Brown 
63426b867d5aSJose E. Roman   Input/Output Parameters:
634320f4b53cSBarry Smith + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
634420f4b53cSBarry Smith - values - An array to use for the values, or `NULL` to have it allocated automatically;
634520f4b53cSBarry Smith            if the user provided `NULL`, it is a borrowed array and should not be freed
634622c1ee49SMatthew G. Knepley 
6347552f7358SJed Brown   Level: intermediate
6348552f7358SJed Brown 
6349a1cb98faSBarry Smith   Notes:
635020f4b53cSBarry Smith   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6351a1cb98faSBarry Smith   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6352a1cb98faSBarry Smith   assembly function, and a user may already have allocated storage for this operation.
6353a1cb98faSBarry Smith 
6354a1cb98faSBarry Smith   A typical use could be
6355a1cb98faSBarry Smith .vb
6356a1cb98faSBarry Smith    values = NULL;
6357a1cb98faSBarry Smith    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6358a1cb98faSBarry Smith    for (cl = 0; cl < clSize; ++cl) {
6359a1cb98faSBarry Smith      <Compute on closure>
6360a1cb98faSBarry Smith    }
6361a1cb98faSBarry Smith    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6362a1cb98faSBarry Smith .ve
6363a1cb98faSBarry Smith   or
6364a1cb98faSBarry Smith .vb
6365a1cb98faSBarry Smith    PetscMalloc1(clMaxSize, &values);
6366a1cb98faSBarry Smith    for (p = pStart; p < pEnd; ++p) {
6367a1cb98faSBarry Smith      clSize = clMaxSize;
6368a1cb98faSBarry Smith      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6369a1cb98faSBarry Smith      for (cl = 0; cl < clSize; ++cl) {
6370a1cb98faSBarry Smith        <Compute on closure>
6371a1cb98faSBarry Smith      }
6372a1cb98faSBarry Smith    }
6373a1cb98faSBarry Smith    PetscFree(values);
6374a1cb98faSBarry Smith .ve
6375a1cb98faSBarry Smith 
637660225df5SJacob Faibussowitsch   Fortran Notes:
637720f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6378a1cb98faSBarry Smith 
63791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6380552f7358SJed Brown @*/
6381d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6382d71ae5a4SJacob Faibussowitsch {
6383d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
6384e8e188d2SZach Atkins   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
63853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6386552f7358SJed Brown }
6387552f7358SJed Brown 
6388d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6389d71ae5a4SJacob Faibussowitsch {
6390e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6391e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6392e5c487bfSMatthew G. Knepley   IS                 clPoints;
6393e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6394e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6395e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6396c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6397c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6398e5c487bfSMatthew G. Knepley 
6399e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6400e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
64019566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6402e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6403e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
64049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
64059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
64069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6407e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
64089566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
64093ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6410e5c487bfSMatthew G. Knepley   }
6411e5c487bfSMatthew G. Knepley   /* Get points */
641207218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6413c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6414c459fbc1SJed Brown     PetscInt dof;
64159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6416c459fbc1SJed Brown     clsize += dof;
6417c459fbc1SJed Brown   }
64189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6419e5c487bfSMatthew G. Knepley   /* Filter points */
6420e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6421e5c487bfSMatthew G. Knepley     PetscInt dep;
6422e5c487bfSMatthew G. Knepley 
64239566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6424e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6425e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6426e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6427e5c487bfSMatthew G. Knepley     ++Np;
6428e5c487bfSMatthew G. Knepley   }
6429e5c487bfSMatthew G. Knepley   /* Get array */
6430e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6431e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6432e5c487bfSMatthew G. Knepley 
6433e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
64349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6435e5c487bfSMatthew G. Knepley       asize += dof;
6436e5c487bfSMatthew G. Knepley     }
6437e5c487bfSMatthew G. Knepley     if (!values) {
64389566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6439e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
64403ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
6441e5c487bfSMatthew G. Knepley     }
64429566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6443e5c487bfSMatthew G. Knepley   } else {
6444e5c487bfSMatthew G. Knepley     array = *values;
6445e5c487bfSMatthew G. Knepley   }
64469566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6447e5c487bfSMatthew G. Knepley   /* Get values */
64489566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
64499566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6450e5c487bfSMatthew G. Knepley   /* Cleanup points */
64519566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6452e5c487bfSMatthew G. Knepley   /* Cleanup array */
64539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6454e5c487bfSMatthew G. Knepley   if (!*values) {
6455e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6456e5c487bfSMatthew G. Knepley     *values = array;
6457e5c487bfSMatthew G. Knepley   } else {
645863a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6459e5c487bfSMatthew G. Knepley     *csize = size;
6460e5c487bfSMatthew G. Knepley   }
64613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6462e5c487bfSMatthew G. Knepley }
6463e5c487bfSMatthew G. Knepley 
6464552f7358SJed Brown /*@C
6465552f7358SJed Brown   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6466552f7358SJed Brown 
6467552f7358SJed Brown   Not collective
6468552f7358SJed Brown 
6469552f7358SJed Brown   Input Parameters:
6470a1cb98faSBarry Smith + dm      - The `DM`
647120f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6472552f7358SJed Brown . v       - The local vector
6473a1cb98faSBarry Smith . point   - The point in the `DM`
647420f4b53cSBarry Smith . csize   - The number of values in the closure, or `NULL`
6475552f7358SJed Brown - values  - The array of values, which is a borrowed array and should not be freed
6476552f7358SJed Brown 
6477552f7358SJed Brown   Level: intermediate
6478552f7358SJed Brown 
6479a1cb98faSBarry Smith   Note:
648020f4b53cSBarry Smith   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6481a1cb98faSBarry Smith 
648260225df5SJacob Faibussowitsch   Fortran Notes:
648320f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6484a1cb98faSBarry Smith 
64851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6486552f7358SJed Brown @*/
6487d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6488d71ae5a4SJacob Faibussowitsch {
6489552f7358SJed Brown   PetscInt size = 0;
6490552f7358SJed Brown 
6491552f7358SJed Brown   PetscFunctionBegin;
6492552f7358SJed Brown   /* Should work without recalculating size */
64939566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6494c9fdaa05SMatthew G. Knepley   *values = NULL;
64953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6496552f7358SJed Brown }
6497552f7358SJed Brown 
6498d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6499d71ae5a4SJacob Faibussowitsch {
65009371c9d4SSatish Balay   *x += y;
65019371c9d4SSatish Balay }
6502d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6503d71ae5a4SJacob Faibussowitsch {
65049371c9d4SSatish Balay   *x = y;
65059371c9d4SSatish Balay }
6506552f7358SJed Brown 
6507d71ae5a4SJacob 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[])
6508d71ae5a4SJacob Faibussowitsch {
6509552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6510552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6511552f7358SJed Brown   PetscScalar    *a;
6512552f7358SJed Brown   PetscInt        off, cind = 0, k;
6513552f7358SJed Brown 
6514552f7358SJed Brown   PetscFunctionBegin;
65159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
65169566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6517552f7358SJed Brown   a = &array[off];
6518552f7358SJed Brown   if (!cdof || setBC) {
651997e99dd9SToby Isaac     if (clperm) {
65209371c9d4SSatish Balay       if (perm) {
6521ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6522552f7358SJed Brown       } else {
6523ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
65249371c9d4SSatish Balay       }
65259371c9d4SSatish Balay     } else {
65269371c9d4SSatish Balay       if (perm) {
6527ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
65289371c9d4SSatish Balay       } else {
6529ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
65309371c9d4SSatish Balay       }
6531552f7358SJed Brown     }
6532552f7358SJed Brown   } else {
65339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
653497e99dd9SToby Isaac     if (clperm) {
65359371c9d4SSatish Balay       if (perm) {
65369371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
65379371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
65389371c9d4SSatish Balay             ++cind;
65399371c9d4SSatish Balay             continue;
65409371c9d4SSatish Balay           }
654197e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6542552f7358SJed Brown         }
6543552f7358SJed Brown       } else {
6544552f7358SJed Brown         for (k = 0; k < dof; ++k) {
65459371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
65469371c9d4SSatish Balay             ++cind;
65479371c9d4SSatish Balay             continue;
65489371c9d4SSatish Balay           }
654997e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
655097e99dd9SToby Isaac         }
655197e99dd9SToby Isaac       }
655297e99dd9SToby Isaac     } else {
655397e99dd9SToby Isaac       if (perm) {
655497e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
65559371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
65569371c9d4SSatish Balay             ++cind;
65579371c9d4SSatish Balay             continue;
65589371c9d4SSatish Balay           }
655997e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
656097e99dd9SToby Isaac         }
656197e99dd9SToby Isaac       } else {
656297e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
65639371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
65649371c9d4SSatish Balay             ++cind;
65659371c9d4SSatish Balay             continue;
65669371c9d4SSatish Balay           }
656797e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
656897e99dd9SToby Isaac         }
6569552f7358SJed Brown       }
6570552f7358SJed Brown     }
6571552f7358SJed Brown   }
65723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6573552f7358SJed Brown }
6574552f7358SJed Brown 
6575d71ae5a4SJacob 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[])
6576d71ae5a4SJacob Faibussowitsch {
6577a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6578a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6579a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6580a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6581a5e93ea8SMatthew G. Knepley 
6582a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
65839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
65849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6585a5e93ea8SMatthew G. Knepley   a = &array[off];
6586a5e93ea8SMatthew G. Knepley   if (cdof) {
65879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
658897e99dd9SToby Isaac     if (clperm) {
658997e99dd9SToby Isaac       if (perm) {
6590a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6591a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
659297e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
659397e99dd9SToby Isaac             cind++;
6594a5e93ea8SMatthew G. Knepley           }
6595a5e93ea8SMatthew G. Knepley         }
6596a5e93ea8SMatthew G. Knepley       } else {
6597a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6598a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
659997e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
660097e99dd9SToby Isaac             cind++;
660197e99dd9SToby Isaac           }
660297e99dd9SToby Isaac         }
660397e99dd9SToby Isaac       }
660497e99dd9SToby Isaac     } else {
660597e99dd9SToby Isaac       if (perm) {
660697e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
660797e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
660897e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
660997e99dd9SToby Isaac             cind++;
661097e99dd9SToby Isaac           }
661197e99dd9SToby Isaac         }
661297e99dd9SToby Isaac       } else {
661397e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
661497e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
661597e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
661697e99dd9SToby Isaac             cind++;
661797e99dd9SToby Isaac           }
6618a5e93ea8SMatthew G. Knepley         }
6619a5e93ea8SMatthew G. Knepley       }
6620a5e93ea8SMatthew G. Knepley     }
6621a5e93ea8SMatthew G. Knepley   }
66223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6623a5e93ea8SMatthew G. Knepley }
6624a5e93ea8SMatthew G. Knepley 
6625d71ae5a4SJacob 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[])
6626d71ae5a4SJacob Faibussowitsch {
6627552f7358SJed Brown   PetscScalar    *a;
66281a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
66291a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
663097e99dd9SToby Isaac   PetscInt        cind = 0, b;
6631552f7358SJed Brown 
6632552f7358SJed Brown   PetscFunctionBegin;
66339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
66349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
66359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
66361a271a75SMatthew G. Knepley   a = &array[foff];
6637552f7358SJed Brown   if (!fcdof || setBC) {
663897e99dd9SToby Isaac     if (clperm) {
66399371c9d4SSatish Balay       if (perm) {
6640ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6641552f7358SJed Brown       } else {
6642ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
66439371c9d4SSatish Balay       }
66449371c9d4SSatish Balay     } else {
66459371c9d4SSatish Balay       if (perm) {
6646ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
66479371c9d4SSatish Balay       } else {
6648ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
66499371c9d4SSatish Balay       }
6650552f7358SJed Brown     }
6651552f7358SJed Brown   } else {
66529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
665397e99dd9SToby Isaac     if (clperm) {
665497e99dd9SToby Isaac       if (perm) {
665597e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
66569371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
66579371c9d4SSatish Balay             ++cind;
66589371c9d4SSatish Balay             continue;
66599371c9d4SSatish Balay           }
666097e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6661552f7358SJed Brown         }
6662552f7358SJed Brown       } else {
666397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
66649371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
66659371c9d4SSatish Balay             ++cind;
66669371c9d4SSatish Balay             continue;
66679371c9d4SSatish Balay           }
666897e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
666997e99dd9SToby Isaac         }
667097e99dd9SToby Isaac       }
667197e99dd9SToby Isaac     } else {
667297e99dd9SToby Isaac       if (perm) {
667397e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
66749371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
66759371c9d4SSatish Balay             ++cind;
66769371c9d4SSatish Balay             continue;
66779371c9d4SSatish Balay           }
667897e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
667997e99dd9SToby Isaac         }
668097e99dd9SToby Isaac       } else {
668197e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
66829371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
66839371c9d4SSatish Balay             ++cind;
66849371c9d4SSatish Balay             continue;
66859371c9d4SSatish Balay           }
668697e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6687552f7358SJed Brown         }
6688552f7358SJed Brown       }
6689552f7358SJed Brown     }
6690552f7358SJed Brown   }
66911a271a75SMatthew G. Knepley   *offset += fdof;
66923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6693552f7358SJed Brown }
6694552f7358SJed Brown 
6695d71ae5a4SJacob 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[])
6696d71ae5a4SJacob Faibussowitsch {
6697a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
66981a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
66991a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
67005da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6701ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6702a5e93ea8SMatthew G. Knepley 
6703a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
67049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
67059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
67069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
67079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
67081a271a75SMatthew G. Knepley   a = &array[foff];
6709a5e93ea8SMatthew G. Knepley   if (fcdof) {
6710ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
67119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
671297e99dd9SToby Isaac     if (clperm) {
671397e99dd9SToby Isaac       if (perm) {
6714ba322698SMatthew G. Knepley         if (comps) {
6715ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6716ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
67179371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
67189371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
67199371c9d4SSatish Balay               ncSet = PETSC_TRUE;
67209371c9d4SSatish Balay             }
67219371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
67229371c9d4SSatish Balay               ++cind;
67239371c9d4SSatish Balay               fcSet = PETSC_TRUE;
67249371c9d4SSatish Balay             }
6725ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6726ba322698SMatthew G. Knepley           }
6727ba322698SMatthew G. Knepley         } else {
672897e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
672997e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
673097e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6731a5e93ea8SMatthew G. Knepley               ++cind;
6732a5e93ea8SMatthew G. Knepley             }
6733a5e93ea8SMatthew G. Knepley           }
6734ba322698SMatthew G. Knepley         }
6735ba322698SMatthew G. Knepley       } else {
6736ba322698SMatthew G. Knepley         if (comps) {
6737ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6738ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
67399371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
67409371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
67419371c9d4SSatish Balay               ncSet = PETSC_TRUE;
67429371c9d4SSatish Balay             }
67439371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
67449371c9d4SSatish Balay               ++cind;
67459371c9d4SSatish Balay               fcSet = PETSC_TRUE;
67469371c9d4SSatish Balay             }
6747ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6748ba322698SMatthew G. Knepley           }
6749a5e93ea8SMatthew G. Knepley         } else {
675097e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
675197e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
675297e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
675397e99dd9SToby Isaac               ++cind;
675497e99dd9SToby Isaac             }
675597e99dd9SToby Isaac           }
675697e99dd9SToby Isaac         }
6757ba322698SMatthew G. Knepley       }
675897e99dd9SToby Isaac     } else {
675997e99dd9SToby Isaac       if (perm) {
6760ba322698SMatthew G. Knepley         if (comps) {
6761ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6762ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
67639371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
67649371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
67659371c9d4SSatish Balay               ncSet = PETSC_TRUE;
67669371c9d4SSatish Balay             }
67679371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
67689371c9d4SSatish Balay               ++cind;
67699371c9d4SSatish Balay               fcSet = PETSC_TRUE;
67709371c9d4SSatish Balay             }
6771ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6772ba322698SMatthew G. Knepley           }
6773ba322698SMatthew G. Knepley         } else {
677497e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
677597e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
677697e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
677797e99dd9SToby Isaac               ++cind;
677897e99dd9SToby Isaac             }
677997e99dd9SToby Isaac           }
6780ba322698SMatthew G. Knepley         }
6781ba322698SMatthew G. Knepley       } else {
6782ba322698SMatthew G. Knepley         if (comps) {
6783ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6784ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
67859371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
67869371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
67879371c9d4SSatish Balay               ncSet = PETSC_TRUE;
67889371c9d4SSatish Balay             }
67899371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
67909371c9d4SSatish Balay               ++cind;
67919371c9d4SSatish Balay               fcSet = PETSC_TRUE;
67929371c9d4SSatish Balay             }
6793ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6794ba322698SMatthew G. Knepley           }
679597e99dd9SToby Isaac         } else {
679697e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
679797e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
679897e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6799a5e93ea8SMatthew G. Knepley               ++cind;
6800a5e93ea8SMatthew G. Knepley             }
6801a5e93ea8SMatthew G. Knepley           }
6802a5e93ea8SMatthew G. Knepley         }
6803a5e93ea8SMatthew G. Knepley       }
6804a5e93ea8SMatthew G. Knepley     }
6805ba322698SMatthew G. Knepley   }
68061a271a75SMatthew G. Knepley   *offset += fdof;
68073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6808a5e93ea8SMatthew G. Knepley }
6809a5e93ea8SMatthew G. Knepley 
6810d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6811d71ae5a4SJacob Faibussowitsch {
6812552f7358SJed Brown   PetscScalar    *array;
68131b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
68141b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6815552f7358SJed Brown 
68161b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
68179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
68189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
68199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
68209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
68219566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6822b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6823b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
6824b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
6825b6ebb6e6SMatthew G. Knepley 
68269371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
68279371c9d4SSatish Balay       dof = 0;
68289371c9d4SSatish Balay       continue;
68299371c9d4SSatish Balay     }
68309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
6831b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
6832b6ebb6e6SMatthew G. Knepley     {
6833b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6834b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
6835b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
6836b6ebb6e6SMatthew G. Knepley 
68379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
68389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6839b6ebb6e6SMatthew G. Knepley       a = &array[coff];
6840b6ebb6e6SMatthew G. Knepley       if (!cdof) {
6841b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6842ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6843b6ebb6e6SMatthew G. Knepley         } else {
6844ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6845b6ebb6e6SMatthew G. Knepley         }
6846b6ebb6e6SMatthew G. Knepley       } else {
68479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6848b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6849b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
68509371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
68519371c9d4SSatish Balay               ++cind;
68529371c9d4SSatish Balay               continue;
68539371c9d4SSatish Balay             }
6854b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
6855b6ebb6e6SMatthew G. Knepley           }
6856b6ebb6e6SMatthew G. Knepley         } else {
6857b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
68589371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
68599371c9d4SSatish Balay               ++cind;
68609371c9d4SSatish Balay               continue;
68619371c9d4SSatish Balay             }
6862b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
6863b6ebb6e6SMatthew G. Knepley           }
6864b6ebb6e6SMatthew G. Knepley         }
6865b6ebb6e6SMatthew G. Knepley       }
6866b6ebb6e6SMatthew G. Knepley     }
6867b6ebb6e6SMatthew G. Knepley   }
68689566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
68693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6870b6ebb6e6SMatthew G. Knepley }
68711b406b76SMatthew G. Knepley 
68721b406b76SMatthew G. Knepley /*@C
687320f4b53cSBarry Smith   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
68741b406b76SMatthew G. Knepley 
68751b406b76SMatthew G. Knepley   Not collective
68761b406b76SMatthew G. Knepley 
68771b406b76SMatthew G. Knepley   Input Parameters:
6878a1cb98faSBarry Smith + dm      - The `DM`
687920f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
68801b406b76SMatthew G. Knepley . v       - The local vector
688120f4b53cSBarry Smith . point   - The point in the `DM`
68821b406b76SMatthew G. Knepley . values  - The array of values
6883a1cb98faSBarry Smith - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6884a1cb98faSBarry Smith          where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
68851b406b76SMatthew G. Knepley 
68861b406b76SMatthew G. Knepley   Level: intermediate
68871b406b76SMatthew G. Knepley 
68881cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
68891b406b76SMatthew G. Knepley @*/
6890d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6891d71ae5a4SJacob Faibussowitsch {
68921b406b76SMatthew G. Knepley   PetscSection    clSection;
68931b406b76SMatthew G. Knepley   IS              clPoints;
68941b406b76SMatthew G. Knepley   PetscScalar    *array;
68951b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
689627f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
6897c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
68981b406b76SMatthew G. Knepley 
68991a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
69001b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
69019566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
69021a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
69031a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
69049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
69059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
69061b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
69079566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
69083ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
69091b406b76SMatthew G. Knepley   }
69101a271a75SMatthew G. Knepley   /* Get points */
691107218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6912c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
6913c459fbc1SJed Brown     PetscInt dof;
69149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6915c459fbc1SJed Brown     clsize += dof;
6916c459fbc1SJed Brown   }
69179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
69181a271a75SMatthew G. Knepley   /* Get array */
69199566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
69201a271a75SMatthew G. Knepley   /* Get values */
6921ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
692297e99dd9SToby Isaac     PetscInt offset = 0, f;
6923552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
692497e99dd9SToby Isaac       const PetscInt    **perms = NULL;
692597e99dd9SToby Isaac       const PetscScalar **flips = NULL;
692697e99dd9SToby Isaac 
69279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6928552f7358SJed Brown       switch (mode) {
6929552f7358SJed Brown       case INSERT_VALUES:
693097e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
693197e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
693297e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
693397e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
69343ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
69359371c9d4SSatish Balay         }
69369371c9d4SSatish Balay         break;
6937552f7358SJed Brown       case INSERT_ALL_VALUES:
693897e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
693997e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
694097e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
694197e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
69423ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
69439371c9d4SSatish Balay         }
69449371c9d4SSatish Balay         break;
6945a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
694697e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
694797e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
694897e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
694997e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
69503ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
69519371c9d4SSatish Balay         }
69529371c9d4SSatish Balay         break;
6953552f7358SJed Brown       case ADD_VALUES:
695497e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
695597e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
695697e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
695797e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
69583ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
69599371c9d4SSatish Balay         }
69609371c9d4SSatish Balay         break;
6961552f7358SJed Brown       case ADD_ALL_VALUES:
696297e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
696397e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
696497e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
696597e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
69663ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
69679371c9d4SSatish Balay         }
69689371c9d4SSatish Balay         break;
6969304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
697097e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
697197e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
697297e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
697397e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
69743ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
69759371c9d4SSatish Balay         }
69769371c9d4SSatish Balay         break;
6977d71ae5a4SJacob Faibussowitsch       default:
6978d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6979552f7358SJed Brown       }
69809566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
69811a271a75SMatthew G. Knepley     }
6982552f7358SJed Brown   } else {
69831a271a75SMatthew G. Knepley     PetscInt            dof, off;
698497e99dd9SToby Isaac     const PetscInt    **perms = NULL;
698597e99dd9SToby Isaac     const PetscScalar **flips = NULL;
69861a271a75SMatthew G. Knepley 
69879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6988552f7358SJed Brown     switch (mode) {
6989552f7358SJed Brown     case INSERT_VALUES:
699097e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
699197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
699297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
699397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
69949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
69953ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
69969371c9d4SSatish Balay       }
69979371c9d4SSatish Balay       break;
6998552f7358SJed Brown     case INSERT_ALL_VALUES:
699997e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
700097e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
700197e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
700297e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70043ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
70059371c9d4SSatish Balay       }
70069371c9d4SSatish Balay       break;
7007a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
700897e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
700997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
701097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
701197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70133ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
70149371c9d4SSatish Balay       }
70159371c9d4SSatish Balay       break;
7016552f7358SJed Brown     case ADD_VALUES:
701797e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
701897e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
701997e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
702097e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70223ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
70239371c9d4SSatish Balay       }
70249371c9d4SSatish Balay       break;
7025552f7358SJed Brown     case ADD_ALL_VALUES:
702697e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
702797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
702897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
702997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70313ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
70329371c9d4SSatish Balay       }
70339371c9d4SSatish Balay       break;
7034304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
703597e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
703697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
703797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
703897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70403ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
70419371c9d4SSatish Balay       }
70429371c9d4SSatish Balay       break;
7043d71ae5a4SJacob Faibussowitsch     default:
7044d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7045552f7358SJed Brown     }
70469566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7047552f7358SJed Brown   }
70481a271a75SMatthew G. Knepley   /* Cleanup points */
70499566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
70501a271a75SMatthew G. Knepley   /* Cleanup array */
70519566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
70523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7053552f7358SJed Brown }
7054552f7358SJed Brown 
70555f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
7056d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7057d71ae5a4SJacob Faibussowitsch {
70585f790a90SMatthew G. Knepley   PetscFunctionBegin;
705911cc89d2SBarry Smith   *contains = PETSC_TRUE;
70605f790a90SMatthew G. Knepley   if (label) {
7061d6177c40SToby Isaac     PetscInt fdof;
70625f790a90SMatthew G. Knepley 
706311cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
706411cc89d2SBarry Smith     if (!*contains) {
70659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
70665f790a90SMatthew G. Knepley       *offset += fdof;
70673ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
70685f790a90SMatthew G. Knepley     }
70695f790a90SMatthew G. Knepley   }
70703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70715f790a90SMatthew G. Knepley }
70725f790a90SMatthew G. Knepley 
707397529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7074d71ae5a4SJacob 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)
7075d71ae5a4SJacob Faibussowitsch {
7076e07394fbSMatthew G. Knepley   PetscSection    clSection;
7077e07394fbSMatthew G. Knepley   IS              clPoints;
7078e07394fbSMatthew G. Knepley   PetscScalar    *array;
7079e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
708097529cf3SJed Brown   const PetscInt *clp;
7081e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
708297e99dd9SToby Isaac   PetscInt        offset = 0, f;
7083e07394fbSMatthew G. Knepley 
7084e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
7085e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
70869566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7087e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7088e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
70899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7090e07394fbSMatthew G. Knepley   /* Get points */
709107218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7092e07394fbSMatthew G. Knepley   /* Get array */
70939566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7094e07394fbSMatthew G. Knepley   /* Get values */
7095e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
709697e99dd9SToby Isaac     const PetscInt    **perms = NULL;
709797e99dd9SToby Isaac     const PetscScalar **flips = NULL;
709811cc89d2SBarry Smith     PetscBool           contains;
709997e99dd9SToby Isaac 
7100e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
7101e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
7102e07394fbSMatthew G. Knepley         PetscInt fdof;
71039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7104e07394fbSMatthew G. Knepley         offset += fdof;
7105e07394fbSMatthew G. Knepley       }
7106e07394fbSMatthew G. Knepley       continue;
7107e07394fbSMatthew G. Knepley     }
71089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7109e07394fbSMatthew G. Knepley     switch (mode) {
7110e07394fbSMatthew G. Knepley     case INSERT_VALUES:
711197e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
711297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
711397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
711497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
711511cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
711611cc89d2SBarry Smith         if (!contains) continue;
71179566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
71189371c9d4SSatish Balay       }
71199371c9d4SSatish Balay       break;
7120e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
712197e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
712297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
712397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
712497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
712511cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
712611cc89d2SBarry Smith         if (!contains) continue;
71279566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
71289371c9d4SSatish Balay       }
71299371c9d4SSatish Balay       break;
7130e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
713197e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
713297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
713397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
713497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
713511cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
713611cc89d2SBarry Smith         if (!contains) continue;
71379566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
71389371c9d4SSatish Balay       }
71399371c9d4SSatish Balay       break;
7140e07394fbSMatthew G. Knepley     case ADD_VALUES:
714197e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
714297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
714397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
714497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
714511cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
714611cc89d2SBarry Smith         if (!contains) continue;
71479566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
71489371c9d4SSatish Balay       }
71499371c9d4SSatish Balay       break;
7150e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
715197e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
715297e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
715397e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
715497e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
715511cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
715611cc89d2SBarry Smith         if (!contains) continue;
71579566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
71589371c9d4SSatish Balay       }
71599371c9d4SSatish Balay       break;
7160d71ae5a4SJacob Faibussowitsch     default:
7161d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7162e07394fbSMatthew G. Knepley     }
71639566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7164e07394fbSMatthew G. Knepley   }
7165e07394fbSMatthew G. Knepley   /* Cleanup points */
71669566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7167e07394fbSMatthew G. Knepley   /* Cleanup array */
71689566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
71693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7170e07394fbSMatthew G. Knepley }
7171e07394fbSMatthew G. Knepley 
7172d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7173d71ae5a4SJacob Faibussowitsch {
7174552f7358SJed Brown   PetscMPIInt rank;
7175552f7358SJed Brown   PetscInt    i, j;
7176552f7358SJed Brown 
7177552f7358SJed Brown   PetscFunctionBegin;
71789566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
717963a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
718063a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
718163a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7182b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
71833ba16761SJacob Faibussowitsch   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7184b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
71859566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7186b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
7187519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
71889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7189552f7358SJed Brown #else
71909566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7191552f7358SJed Brown #endif
7192552f7358SJed Brown     }
71939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7194552f7358SJed Brown   }
71953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7196552f7358SJed Brown }
7197552f7358SJed Brown 
719805586334SMatthew G. Knepley /*
719905586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
720005586334SMatthew G. Knepley 
720105586334SMatthew G. Knepley   Input Parameters:
720205586334SMatthew G. Knepley + section - The section for this data layout
720336fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
720405586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
720505586334SMatthew G. Knepley . off     - The global offset of this point
720605586334SMatthew G. Knepley . loff    - The local offset of each field
7207a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
720805586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
720905586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
721005586334SMatthew G. Knepley 
721105586334SMatthew G. Knepley   Output Parameter:
721205586334SMatthew G. Knepley . indices - Indices for dofs on this point
721305586334SMatthew G. Knepley 
721405586334SMatthew G. Knepley   Level: developer
721505586334SMatthew G. Knepley 
721605586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
721705586334SMatthew G. Knepley */
7218d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7219d71ae5a4SJacob Faibussowitsch {
7220e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
7221552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
7222552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7223552f7358SJed Brown   PetscInt        cind = 0, k;
7224552f7358SJed Brown 
7225552f7358SJed Brown   PetscFunctionBegin;
722608401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
72279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
72289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7229552f7358SJed Brown   if (!cdof || setBC) {
723005586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
723105586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
723205586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
723305586334SMatthew G. Knepley 
723405586334SMatthew G. Knepley       indices[ind] = off + k;
7235552f7358SJed Brown     }
7236552f7358SJed Brown   } else {
72379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
72384acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
723905586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
724005586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
724105586334SMatthew G. Knepley 
72424acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
72434acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
724405586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
72454acb8e1eSToby Isaac         ++cind;
72464acb8e1eSToby Isaac       } else {
724736fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
7248552f7358SJed Brown       }
7249552f7358SJed Brown     }
7250552f7358SJed Brown   }
7251e6ccafaeSMatthew G Knepley   *loff += dof;
72523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7253552f7358SJed Brown }
7254552f7358SJed Brown 
72557e29afd2SMatthew G. Knepley /*
725636fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
72577e29afd2SMatthew G. Knepley 
725836fa2b79SJed Brown  Input Parameters:
725936fa2b79SJed Brown + section - a section (global or local)
726020f4b53cSBarry Smith - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
726136fa2b79SJed Brown . point - point within section
726236fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
726336fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
726436fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
726536fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
726636fa2b79SJed Brown . permsoff - offset
726736fa2b79SJed Brown - indperm - index permutation
726836fa2b79SJed Brown 
726936fa2b79SJed Brown  Output Parameter:
727036fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
727136fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
727236fa2b79SJed Brown 
727336fa2b79SJed Brown  Notes:
727436fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
727536fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
727636fa2b79SJed Brown  in the local vector.
727736fa2b79SJed Brown 
727836fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
727936fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
728036fa2b79SJed Brown 
728136fa2b79SJed Brown  Developer Note:
728236fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
728336fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
728436fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
728536fa2b79SJed Brown 
728636fa2b79SJed Brown  Example:
728736fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
728836fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
728936fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
729036fa2b79SJed 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.
729136fa2b79SJed Brown 
729236fa2b79SJed Brown  Level: developer
72937e29afd2SMatthew G. Knepley */
7294d71ae5a4SJacob 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[])
7295d71ae5a4SJacob Faibussowitsch {
7296552f7358SJed Brown   PetscInt numFields, foff, f;
7297552f7358SJed Brown 
7298552f7358SJed Brown   PetscFunctionBegin;
729908401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
73009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7301552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
73024acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
7303552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
73044acb8e1eSToby Isaac     PetscInt        cind = 0, b;
73054acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7306552f7358SJed Brown 
73079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
73089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7309552f7358SJed Brown     if (!cfdof || setBC) {
731005586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
731105586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
731205586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
731305586334SMatthew G. Knepley 
731405586334SMatthew G. Knepley         indices[ind] = off + foff + b;
731505586334SMatthew G. Knepley       }
7316552f7358SJed Brown     } else {
73179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
731805586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
731905586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
732005586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
732105586334SMatthew G. Knepley 
73224acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
732305586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
7324552f7358SJed Brown           ++cind;
7325552f7358SJed Brown         } else {
732636fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7327552f7358SJed Brown         }
7328552f7358SJed Brown       }
7329552f7358SJed Brown     }
733036fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7331552f7358SJed Brown     foffs[f] += fdof;
7332552f7358SJed Brown   }
73333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7334552f7358SJed Brown }
7335552f7358SJed Brown 
73367e29afd2SMatthew G. Knepley /*
73377e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
73387e29afd2SMatthew G. Knepley 
73397e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7340645102dcSJed Brown 
7341645102dcSJed Brown  Notes:
7342645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7343645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
73447e29afd2SMatthew G. Knepley */
7345d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7346d71ae5a4SJacob Faibussowitsch {
73477e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
73487e29afd2SMatthew G. Knepley 
73497e29afd2SMatthew G. Knepley   PetscFunctionBegin;
73509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
73517e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
73527e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
73537e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
73547e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
73557e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
73567e29afd2SMatthew G. Knepley 
73579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
73589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
73599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7360645102dcSJed Brown     if (!cfdof) {
736105586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
736205586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
736305586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
736405586334SMatthew G. Knepley 
736505586334SMatthew G. Knepley         indices[ind] = foff + b;
736605586334SMatthew G. Knepley       }
73677e29afd2SMatthew G. Knepley     } else {
73689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
736905586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
737005586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
737105586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
737205586334SMatthew G. Knepley 
73737e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
737405586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
73757e29afd2SMatthew G. Knepley           ++cind;
73767e29afd2SMatthew G. Knepley         } else {
737705586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
73787e29afd2SMatthew G. Knepley         }
73797e29afd2SMatthew G. Knepley       }
73807e29afd2SMatthew G. Knepley     }
73817e29afd2SMatthew G. Knepley     foffs[f] += fdof;
73827e29afd2SMatthew G. Knepley   }
73833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
73847e29afd2SMatthew G. Knepley }
73857e29afd2SMatthew G. Knepley 
7386d71ae5a4SJacob Faibussowitsch 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)
7387d71ae5a4SJacob Faibussowitsch {
7388d3d1a6afSToby Isaac   Mat             cMat;
7389d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7390d3d1a6afSToby Isaac   IS              aIS;
7391d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7392d3d1a6afSToby Isaac   const PetscInt *anchors;
7393e17c06e0SMatthew G. Knepley   PetscInt        numFields, f, p, q, newP = 0;
7394d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7395d3d1a6afSToby Isaac   PetscInt       *newPoints, *indices, *newIndices;
7396d3d1a6afSToby Isaac   PetscInt        maxAnchor, maxDof;
7397d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7398d3d1a6afSToby Isaac   PetscInt       *pointMatOffsets[32];
7399d3d1a6afSToby Isaac   PetscInt       *newPointOffsets[32];
7400d3d1a6afSToby Isaac   PetscScalar    *pointMat[32];
74016ecaa68aSToby Isaac   PetscScalar    *newValues      = NULL, *tmpValues;
7402d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7403d3d1a6afSToby Isaac 
7404d3d1a6afSToby Isaac   PetscFunctionBegin;
7405d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7406d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
74079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7408d3d1a6afSToby Isaac 
74099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7410d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7411d3d1a6afSToby Isaac   if (aSec) {
74129566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
74139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
74149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7415d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7416d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7417d3d1a6afSToby Isaac      * into the global matrix anyway) */
7418d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7419d3d1a6afSToby Isaac       PetscInt b    = points[p];
74204b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7421d3d1a6afSToby Isaac 
74229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7423ad540459SPierre Jolivet       if (!bSecDof) continue;
742448a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7425d3d1a6afSToby Isaac       if (bDof) {
7426d3d1a6afSToby Isaac         /* this point is constrained */
7427d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7428d3d1a6afSToby Isaac         PetscInt bOff, q;
7429d3d1a6afSToby Isaac 
7430d3d1a6afSToby Isaac         anyConstrained = PETSC_TRUE;
7431d3d1a6afSToby Isaac         newNumPoints += bDof;
74329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7433d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7434d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q];
7435d3d1a6afSToby Isaac           PetscInt aDof;
7436d3d1a6afSToby Isaac 
74379566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7438d3d1a6afSToby Isaac           newNumIndices += aDof;
7439d3d1a6afSToby Isaac           for (f = 0; f < numFields; ++f) {
7440d3d1a6afSToby Isaac             PetscInt fDof;
7441d3d1a6afSToby Isaac 
74429566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7443d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7444d3d1a6afSToby Isaac           }
7445d3d1a6afSToby Isaac         }
74469371c9d4SSatish Balay       } else {
7447d3d1a6afSToby Isaac         /* this point is not constrained */
7448d3d1a6afSToby Isaac         newNumPoints++;
74494b2f2278SToby Isaac         newNumIndices += bSecDof;
7450d3d1a6afSToby Isaac         for (f = 0; f < numFields; ++f) {
7451d3d1a6afSToby Isaac           PetscInt fDof;
7452d3d1a6afSToby Isaac 
74539566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7454d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7455d3d1a6afSToby Isaac         }
7456d3d1a6afSToby Isaac       }
7457d3d1a6afSToby Isaac     }
7458d3d1a6afSToby Isaac   }
7459d3d1a6afSToby Isaac   if (!anyConstrained) {
746072b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
746172b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
746272b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
746372b80496SMatthew G. Knepley     if (outValues) *outValues = NULL;
74649566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
74653ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7466d3d1a6afSToby Isaac   }
7467d3d1a6afSToby Isaac 
74686ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
74696ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
74706ecaa68aSToby Isaac 
7471f13f9184SToby Isaac   for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7472d3d1a6afSToby Isaac 
74736ecaa68aSToby Isaac   if (!outPoints && !outValues) {
74746ecaa68aSToby Isaac     if (offsets) {
7475ad540459SPierre Jolivet       for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
74766ecaa68aSToby Isaac     }
74779566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
74783ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
74796ecaa68aSToby Isaac   }
74806ecaa68aSToby Isaac 
74811dca8a05SBarry 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);
7482d3d1a6afSToby Isaac 
74839566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7484d3d1a6afSToby Isaac 
7485d3d1a6afSToby Isaac   /* workspaces */
7486d3d1a6afSToby Isaac   if (numFields) {
7487d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
74889566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
74899566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7490d3d1a6afSToby Isaac     }
74919371c9d4SSatish Balay   } else {
74929566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
74939566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0]));
7494d3d1a6afSToby Isaac   }
7495d3d1a6afSToby Isaac 
7496d3d1a6afSToby Isaac   /* get workspaces for the point-to-point matrices */
7497d3d1a6afSToby Isaac   if (numFields) {
74984b2f2278SToby Isaac     PetscInt totalOffset, totalMatOffset;
74994b2f2278SToby Isaac 
7500d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7501d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
75024b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7503d3d1a6afSToby Isaac 
75049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
75054b2f2278SToby Isaac       if (!bSecDof) {
75064b2f2278SToby Isaac         for (f = 0; f < numFields; f++) {
75074b2f2278SToby Isaac           newPointOffsets[f][p + 1] = 0;
75084b2f2278SToby Isaac           pointMatOffsets[f][p + 1] = 0;
75094b2f2278SToby Isaac         }
75104b2f2278SToby Isaac         continue;
75114b2f2278SToby Isaac       }
751248a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7513d3d1a6afSToby Isaac       if (bDof) {
7514d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7515d3d1a6afSToby Isaac           PetscInt fDof, q, bOff, allFDof = 0;
7516d3d1a6afSToby Isaac 
75179566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
75189566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7519d3d1a6afSToby Isaac           for (q = 0; q < bDof; q++) {
7520d3d1a6afSToby Isaac             PetscInt a = anchors[bOff + q];
7521d3d1a6afSToby Isaac             PetscInt aFDof;
7522d3d1a6afSToby Isaac 
75239566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
7524d3d1a6afSToby Isaac             allFDof += aFDof;
7525d3d1a6afSToby Isaac           }
7526d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = allFDof;
7527d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = fDof * allFDof;
7528d3d1a6afSToby Isaac         }
75299371c9d4SSatish Balay       } else {
7530d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7531d3d1a6afSToby Isaac           PetscInt fDof;
7532d3d1a6afSToby Isaac 
75339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7534d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = fDof;
7535d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = 0;
7536d3d1a6afSToby Isaac         }
7537d3d1a6afSToby Isaac       }
7538d3d1a6afSToby Isaac     }
75394b2f2278SToby Isaac     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
75404b2f2278SToby Isaac       newPointOffsets[f][0] = totalOffset;
75414b2f2278SToby Isaac       pointMatOffsets[f][0] = totalMatOffset;
7542d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7543d3d1a6afSToby Isaac         newPointOffsets[f][p + 1] += newPointOffsets[f][p];
7544d3d1a6afSToby Isaac         pointMatOffsets[f][p + 1] += pointMatOffsets[f][p];
7545d3d1a6afSToby Isaac       }
754619f70fd5SToby Isaac       totalOffset    = newPointOffsets[f][numPoints];
754719f70fd5SToby Isaac       totalMatOffset = pointMatOffsets[f][numPoints];
75489566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7549d3d1a6afSToby Isaac     }
75509371c9d4SSatish Balay   } else {
7551d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7552d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
75534b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7554d3d1a6afSToby Isaac 
75559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
75564b2f2278SToby Isaac       if (!bSecDof) {
75574b2f2278SToby Isaac         newPointOffsets[0][p + 1] = 0;
75584b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = 0;
75594b2f2278SToby Isaac         continue;
75604b2f2278SToby Isaac       }
756148a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7562d3d1a6afSToby Isaac       if (bDof) {
75634b2f2278SToby Isaac         PetscInt bOff, q, allDof = 0;
7564d3d1a6afSToby Isaac 
75659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7566d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7567d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aDof;
7568d3d1a6afSToby Isaac 
75699566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7570d3d1a6afSToby Isaac           allDof += aDof;
7571d3d1a6afSToby Isaac         }
7572d3d1a6afSToby Isaac         newPointOffsets[0][p + 1] = allDof;
75734b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = bSecDof * allDof;
75749371c9d4SSatish Balay       } else {
75754b2f2278SToby Isaac         newPointOffsets[0][p + 1] = bSecDof;
7576d3d1a6afSToby Isaac         pointMatOffsets[0][p + 1] = 0;
7577d3d1a6afSToby Isaac       }
7578d3d1a6afSToby Isaac     }
7579d3d1a6afSToby Isaac     newPointOffsets[0][0] = 0;
7580d3d1a6afSToby Isaac     pointMatOffsets[0][0] = 0;
7581d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7582d3d1a6afSToby Isaac       newPointOffsets[0][p + 1] += newPointOffsets[0][p];
7583d3d1a6afSToby Isaac       pointMatOffsets[0][p + 1] += pointMatOffsets[0][p];
7584d3d1a6afSToby Isaac     }
75859566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7586d3d1a6afSToby Isaac   }
7587d3d1a6afSToby Isaac 
75886ecaa68aSToby Isaac   /* output arrays */
75899566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
75906ecaa68aSToby Isaac 
7591d3d1a6afSToby Isaac   /* get the point-to-point matrices; construct newPoints */
75929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
75939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
75949566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices));
75959566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7596d3d1a6afSToby Isaac   if (numFields) {
7597d3d1a6afSToby Isaac     for (p = 0, newP = 0; p < numPoints; p++) {
7598d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7599d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
76004b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7601d3d1a6afSToby Isaac 
76029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7603ad540459SPierre Jolivet       if (!bSecDof) continue;
760448a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7605d3d1a6afSToby Isaac       if (bDof) {
7606d3d1a6afSToby Isaac         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
7607d3d1a6afSToby Isaac 
7608d3d1a6afSToby Isaac         fStart[0] = 0;
7609d3d1a6afSToby Isaac         fEnd[0]   = 0;
7610d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7611d3d1a6afSToby Isaac           PetscInt fDof;
7612d3d1a6afSToby Isaac 
76139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7614d3d1a6afSToby Isaac           fStart[f + 1] = fStart[f] + fDof;
7615d3d1a6afSToby Isaac           fEnd[f + 1]   = fStart[f + 1];
7616d3d1a6afSToby Isaac         }
76179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
76189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
7619d3d1a6afSToby Isaac 
7620d3d1a6afSToby Isaac         fAnchorStart[0] = 0;
7621d3d1a6afSToby Isaac         fAnchorEnd[0]   = 0;
7622d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7623d3d1a6afSToby Isaac           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7624d3d1a6afSToby Isaac 
7625d3d1a6afSToby Isaac           fAnchorStart[f + 1] = fAnchorStart[f] + fDof;
7626d3d1a6afSToby Isaac           fAnchorEnd[f + 1]   = fAnchorStart[f + 1];
7627d3d1a6afSToby Isaac         }
76289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7629d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7630d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7631d3d1a6afSToby Isaac 
7632d3d1a6afSToby Isaac           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7633d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7634d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
76359566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
76369566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7637d3d1a6afSToby Isaac         }
7638d3d1a6afSToby Isaac         newP += bDof;
7639d3d1a6afSToby Isaac 
76406ecaa68aSToby Isaac         if (outValues) {
7641d3d1a6afSToby Isaac           /* get the point-to-point submatrix */
764248a46eb9SPierre Jolivet           for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p]));
7643d3d1a6afSToby Isaac         }
76449371c9d4SSatish Balay       } else {
7645d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7646d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7647d3d1a6afSToby Isaac         newP++;
7648d3d1a6afSToby Isaac       }
7649d3d1a6afSToby Isaac     }
7650d3d1a6afSToby Isaac   } else {
7651d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7652d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7653d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
76544b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7655d3d1a6afSToby Isaac 
76569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7657ad540459SPierre Jolivet       if (!bSecDof) continue;
765848a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7659d3d1a6afSToby Isaac       if (bDof) {
7660d3d1a6afSToby Isaac         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7661d3d1a6afSToby Isaac 
76629566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
76639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7664d3d1a6afSToby Isaac 
76659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7666d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7667d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7668d3d1a6afSToby Isaac 
7669d3d1a6afSToby Isaac           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7670d3d1a6afSToby Isaac 
7671d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7672d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
76739566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
76749566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7675d3d1a6afSToby Isaac         }
7676d3d1a6afSToby Isaac         newP += bDof;
7677d3d1a6afSToby Isaac 
7678d3d1a6afSToby Isaac         /* get the point-to-point submatrix */
767948a46eb9SPierre Jolivet         if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p]));
76809371c9d4SSatish Balay       } else {
7681d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7682d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7683d3d1a6afSToby Isaac         newP++;
7684d3d1a6afSToby Isaac       }
7685d3d1a6afSToby Isaac     }
7686d3d1a6afSToby Isaac   }
7687d3d1a6afSToby Isaac 
76886ecaa68aSToby Isaac   if (outValues) {
76899566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
76909566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices));
7691d3d1a6afSToby Isaac     /* multiply constraints on the right */
7692d3d1a6afSToby Isaac     if (numFields) {
7693d3d1a6afSToby Isaac       for (f = 0; f < numFields; f++) {
7694d3d1a6afSToby Isaac         PetscInt oldOff = offsets[f];
7695d3d1a6afSToby Isaac 
7696d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7697d3d1a6afSToby Isaac           PetscInt cStart = newPointOffsets[f][p];
7698d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7699d3d1a6afSToby Isaac           PetscInt c, r, k;
7700d3d1a6afSToby Isaac           PetscInt dof;
7701d3d1a6afSToby Isaac 
77029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7703ad540459SPierre Jolivet           if (!dof) continue;
7704d3d1a6afSToby Isaac           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7705d3d1a6afSToby Isaac             PetscInt           nCols = newPointOffsets[f][p + 1] - cStart;
7706d3d1a6afSToby Isaac             const PetscScalar *mat   = pointMat[f] + pointMatOffsets[f][p];
7707d3d1a6afSToby Isaac 
7708d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7709d3d1a6afSToby Isaac               for (c = 0; c < nCols; c++) {
7710ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7711d3d1a6afSToby Isaac               }
7712d3d1a6afSToby Isaac             }
77139371c9d4SSatish Balay           } else {
7714d3d1a6afSToby Isaac             /* copy this column as is */
7715d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7716ad540459SPierre Jolivet               for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7717d3d1a6afSToby Isaac             }
7718d3d1a6afSToby Isaac           }
7719d3d1a6afSToby Isaac           oldOff += dof;
7720d3d1a6afSToby Isaac         }
7721d3d1a6afSToby Isaac       }
77229371c9d4SSatish Balay     } else {
7723d3d1a6afSToby Isaac       PetscInt oldOff = 0;
7724d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7725d3d1a6afSToby Isaac         PetscInt cStart = newPointOffsets[0][p];
7726d3d1a6afSToby Isaac         PetscInt b      = points[2 * p];
7727d3d1a6afSToby Isaac         PetscInt c, r, k;
7728d3d1a6afSToby Isaac         PetscInt dof;
7729d3d1a6afSToby Isaac 
77309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, b, &dof));
7731ad540459SPierre Jolivet         if (!dof) continue;
7732d3d1a6afSToby Isaac         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7733d3d1a6afSToby Isaac           PetscInt           nCols = newPointOffsets[0][p + 1] - cStart;
7734d3d1a6afSToby Isaac           const PetscScalar *mat   = pointMat[0] + pointMatOffsets[0][p];
7735d3d1a6afSToby Isaac 
7736d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7737d3d1a6afSToby Isaac             for (c = 0; c < nCols; c++) {
7738ad540459SPierre Jolivet               for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7739d3d1a6afSToby Isaac             }
7740d3d1a6afSToby Isaac           }
77419371c9d4SSatish Balay         } else {
7742d3d1a6afSToby Isaac           /* copy this column as is */
7743d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7744ad540459SPierre Jolivet             for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7745d3d1a6afSToby Isaac           }
7746d3d1a6afSToby Isaac         }
7747d3d1a6afSToby Isaac         oldOff += dof;
7748d3d1a6afSToby Isaac       }
7749d3d1a6afSToby Isaac     }
7750d3d1a6afSToby Isaac 
77516ecaa68aSToby Isaac     if (multiplyLeft) {
77529566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues));
77539566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices));
7754d3d1a6afSToby Isaac       /* multiply constraints transpose on the left */
7755d3d1a6afSToby Isaac       if (numFields) {
7756d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7757d3d1a6afSToby Isaac           PetscInt oldOff = offsets[f];
7758d3d1a6afSToby Isaac 
7759d3d1a6afSToby Isaac           for (p = 0; p < numPoints; p++) {
7760d3d1a6afSToby Isaac             PetscInt rStart = newPointOffsets[f][p];
7761d3d1a6afSToby Isaac             PetscInt b      = points[2 * p];
7762d3d1a6afSToby Isaac             PetscInt c, r, k;
7763d3d1a6afSToby Isaac             PetscInt dof;
7764d3d1a6afSToby Isaac 
77659566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7766d3d1a6afSToby Isaac             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7767d3d1a6afSToby Isaac               PetscInt                          nRows = newPointOffsets[f][p + 1] - rStart;
7768d3d1a6afSToby Isaac               const PetscScalar *PETSC_RESTRICT mat   = pointMat[f] + pointMatOffsets[f][p];
7769d3d1a6afSToby Isaac 
7770d3d1a6afSToby Isaac               for (r = 0; r < nRows; r++) {
7771d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7772ad540459SPierre Jolivet                   for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7773d3d1a6afSToby Isaac                 }
7774d3d1a6afSToby Isaac               }
77759371c9d4SSatish Balay             } else {
7776d3d1a6afSToby Isaac               /* copy this row as is */
7777d3d1a6afSToby Isaac               for (r = 0; r < dof; r++) {
7778ad540459SPierre Jolivet                 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7779d3d1a6afSToby Isaac               }
7780d3d1a6afSToby Isaac             }
7781d3d1a6afSToby Isaac             oldOff += dof;
7782d3d1a6afSToby Isaac           }
7783d3d1a6afSToby Isaac         }
77849371c9d4SSatish Balay       } else {
7785d3d1a6afSToby Isaac         PetscInt oldOff = 0;
7786d3d1a6afSToby Isaac 
7787d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7788d3d1a6afSToby Isaac           PetscInt rStart = newPointOffsets[0][p];
7789d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7790d3d1a6afSToby Isaac           PetscInt c, r, k;
7791d3d1a6afSToby Isaac           PetscInt dof;
7792d3d1a6afSToby Isaac 
77939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, b, &dof));
7794d3d1a6afSToby Isaac           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7795d3d1a6afSToby Isaac             PetscInt                          nRows = newPointOffsets[0][p + 1] - rStart;
7796d3d1a6afSToby Isaac             const PetscScalar *PETSC_RESTRICT mat   = pointMat[0] + pointMatOffsets[0][p];
7797d3d1a6afSToby Isaac 
7798d3d1a6afSToby Isaac             for (r = 0; r < nRows; r++) {
7799d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7800ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7801d3d1a6afSToby Isaac               }
7802d3d1a6afSToby Isaac             }
78039371c9d4SSatish Balay           } else {
7804d3d1a6afSToby Isaac             /* copy this row as is */
78059fc93327SToby Isaac             for (r = 0; r < dof; r++) {
7806ad540459SPierre Jolivet               for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7807d3d1a6afSToby Isaac             }
7808d3d1a6afSToby Isaac           }
7809d3d1a6afSToby Isaac           oldOff += dof;
7810d3d1a6afSToby Isaac         }
7811d3d1a6afSToby Isaac       }
7812d3d1a6afSToby Isaac 
78139566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
78149371c9d4SSatish Balay     } else {
78156ecaa68aSToby Isaac       newValues = tmpValues;
78166ecaa68aSToby Isaac     }
78176ecaa68aSToby Isaac   }
78186ecaa68aSToby Isaac 
7819d3d1a6afSToby Isaac   /* clean up */
78209566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices));
78219566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
78226ecaa68aSToby Isaac 
7823d3d1a6afSToby Isaac   if (numFields) {
7824d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
78259566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
78269566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
78279566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7828d3d1a6afSToby Isaac     }
78299371c9d4SSatish Balay   } else {
78309566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
78319566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
78329566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0]));
7833d3d1a6afSToby Isaac   }
78349566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
7835d3d1a6afSToby Isaac 
7836d3d1a6afSToby Isaac   /* output */
78376ecaa68aSToby Isaac   if (outPoints) {
7838d3d1a6afSToby Isaac     *outPoints = newPoints;
78399371c9d4SSatish Balay   } else {
78409566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
78416ecaa68aSToby Isaac   }
7842ad540459SPierre Jolivet   if (outValues) *outValues = newValues;
7843ad540459SPierre Jolivet   for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
78443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7845d3d1a6afSToby Isaac }
7846d3d1a6afSToby Isaac 
78474a1e0b3eSMatthew G. Knepley /*@C
784871f0bbf9SMatthew G. Knepley   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
78497cd05799SMatthew G. Knepley 
78507cd05799SMatthew G. Knepley   Not collective
78517cd05799SMatthew G. Knepley 
78527cd05799SMatthew G. Knepley   Input Parameters:
7853a1cb98faSBarry Smith + dm         - The `DM`
7854a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
7855a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
785671f0bbf9SMatthew G. Knepley . point      - The point defining the closure
785771f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
78587cd05799SMatthew G. Knepley 
785971f0bbf9SMatthew G. Knepley   Output Parameters:
786071f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
786171f0bbf9SMatthew G. Knepley . indices    - The dof indices
786220f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
786320f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
78647cd05799SMatthew G. Knepley 
7865a1cb98faSBarry Smith   Level: advanced
786636fa2b79SJed Brown 
7867a1cb98faSBarry Smith   Notes:
7868a1cb98faSBarry Smith   Must call `DMPlexRestoreClosureIndices()` to free allocated memory
7869a1cb98faSBarry Smith 
787020f4b53cSBarry Smith   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
787120f4b53cSBarry Smith   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
787236fa2b79SJed Brown   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
787320f4b53cSBarry Smith   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
787436fa2b79SJed Brown   indices (with the above semantics) are implied.
78757cd05799SMatthew G. Knepley 
78761cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
7877a1cb98faSBarry Smith           `PetscSection`, `DMGetGlobalSection()`
78784a1e0b3eSMatthew G. Knepley @*/
7879d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7880d71ae5a4SJacob Faibussowitsch {
788171f0bbf9SMatthew G. Knepley   /* Closure ordering */
78827773e69fSMatthew G. Knepley   PetscSection    clSection;
78837773e69fSMatthew G. Knepley   IS              clPoints;
788471f0bbf9SMatthew G. Knepley   const PetscInt *clp;
788571f0bbf9SMatthew G. Knepley   PetscInt       *points;
788671f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
788771f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
78884acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
788971f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
789071f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
789171f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
789271f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
789371f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
789471f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
789571f0bbf9SMatthew G. Knepley 
789671f0bbf9SMatthew G. Knepley   PetscInt *idx;
789771f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
789871f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
78997773e69fSMatthew G. Knepley 
790071f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
79017773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
79027773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
790336fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
79044f572ea9SToby Isaac   if (numIndices) PetscAssertPointer(numIndices, 6);
79054f572ea9SToby Isaac   if (indices) PetscAssertPointer(indices, 7);
79064f572ea9SToby Isaac   if (outOffsets) PetscAssertPointer(outOffsets, 8);
79074f572ea9SToby Isaac   if (values) PetscAssertPointer(values, 9);
79089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
790963a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
79109566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
791171f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
791207218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7913c459fbc1SJed Brown   if (useClPerm) {
7914c459fbc1SJed Brown     PetscInt depth, clsize;
79159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7916c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
7917c459fbc1SJed Brown       PetscInt dof;
79189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7919c459fbc1SJed Brown       clsize += dof;
7920c459fbc1SJed Brown     }
79219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7922c459fbc1SJed Brown   }
792371f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
792471f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
79257773e69fSMatthew G. Knepley     PetscInt dof, fdof;
79267773e69fSMatthew G. Knepley 
79279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
79287773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
79299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
79307773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
79317773e69fSMatthew G. Knepley     }
793271f0bbf9SMatthew G. Knepley     Ni += dof;
79337773e69fSMatthew G. Knepley   }
79347773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
79351dca8a05SBarry 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);
793671f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
793771f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
79389566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
79399566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
794071f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
794171f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
794271f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
79436ecaa68aSToby Isaac 
794471f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
794571f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
794671f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
794771f0bbf9SMatthew G. Knepley 
79489566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
79499566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
795071f0bbf9SMatthew G. Knepley         if (flip) {
795171f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
795271f0bbf9SMatthew G. Knepley 
795371f0bbf9SMatthew G. Knepley           if (!valCopy) {
79549566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
795571f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
795671f0bbf9SMatthew G. Knepley             *values = valCopy;
795771f0bbf9SMatthew G. Knepley           }
795871f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
795971f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
796071f0bbf9SMatthew G. Knepley 
796171f0bbf9SMatthew G. Knepley             for (k = 0; k < Ni; ++k) {
796271f0bbf9SMatthew G. Knepley               valCopy[Ni * (foffset + i) + k] *= fval;
796371f0bbf9SMatthew G. Knepley               valCopy[Ni * k + (foffset + i)] *= fval;
79646ecaa68aSToby Isaac             }
79656ecaa68aSToby Isaac           }
796671f0bbf9SMatthew G. Knepley         }
796771f0bbf9SMatthew G. Knepley         foffset += fdof;
796871f0bbf9SMatthew G. Knepley       }
796971f0bbf9SMatthew G. Knepley     }
797071f0bbf9SMatthew G. Knepley   }
797171f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
79729566063dSJacob Faibussowitsch   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
797371f0bbf9SMatthew G. Knepley   if (NclC) {
79749566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
797571f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
79769566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
79779566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
797871f0bbf9SMatthew G. Knepley     }
797971f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
79809566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
79819566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
798271f0bbf9SMatthew G. Knepley     }
79839566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
798471f0bbf9SMatthew G. Knepley     Ncl    = NclC;
798571f0bbf9SMatthew G. Knepley     Ni     = NiC;
798671f0bbf9SMatthew G. Knepley     points = pointsC;
798771f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
798871f0bbf9SMatthew G. Knepley   }
798971f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
79909566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
799171f0bbf9SMatthew G. Knepley   if (Nf) {
799271f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
799371f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
799471f0bbf9SMatthew G. Knepley 
79959371c9d4SSatish Balay     if (outOffsets) {
79969371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
79979371c9d4SSatish Balay     }
79989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
799971f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
800071f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
800171f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
800271f0bbf9SMatthew G. Knepley 
80039566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
80047773e69fSMatthew G. Knepley       }
80057773e69fSMatthew G. Knepley     } else {
800671f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
800771f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
800871f0bbf9SMatthew G. Knepley 
80099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
801071f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
801171f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
801271f0bbf9SMatthew G. Knepley          * global section. */
80139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
801471f0bbf9SMatthew G. Knepley       }
801571f0bbf9SMatthew G. Knepley     }
801671f0bbf9SMatthew G. Knepley   } else {
801771f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
801871f0bbf9SMatthew G. Knepley 
801971f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
802071f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
80214acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
80224acb8e1eSToby Isaac 
80239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
802471f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
802571f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
80269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
80277773e69fSMatthew G. Knepley     }
80287773e69fSMatthew G. Knepley   }
802971f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
803071f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
80319566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
80329566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
80334acb8e1eSToby Isaac   }
803471f0bbf9SMatthew G. Knepley   if (NclC) {
80359566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
80367773e69fSMatthew G. Knepley   } else {
80379566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
80387773e69fSMatthew G. Knepley   }
803971f0bbf9SMatthew G. Knepley 
804071f0bbf9SMatthew G. Knepley   if (numIndices) *numIndices = Ni;
804171f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
80423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
80437773e69fSMatthew G. Knepley }
80447773e69fSMatthew G. Knepley 
80457cd05799SMatthew G. Knepley /*@C
804671f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
80477cd05799SMatthew G. Knepley 
80487cd05799SMatthew G. Knepley   Not collective
80497cd05799SMatthew G. Knepley 
80507cd05799SMatthew G. Knepley   Input Parameters:
8051a1cb98faSBarry Smith + dm         - The `DM`
8052a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
8053a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
805471f0bbf9SMatthew G. Knepley . point      - The point defining the closure
805571f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
805671f0bbf9SMatthew G. Knepley 
805771f0bbf9SMatthew G. Knepley   Output Parameters:
805871f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
805971f0bbf9SMatthew G. Knepley . indices    - The dof indices
806020f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
806120f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
806271f0bbf9SMatthew G. Knepley 
8063a1cb98faSBarry Smith   Level: advanced
806471f0bbf9SMatthew G. Knepley 
8065a1cb98faSBarry Smith   Notes:
8066a1cb98faSBarry Smith   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
8067a1cb98faSBarry Smith 
8068a1cb98faSBarry Smith   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
806971f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
807071f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
807171f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
807271f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
80737cd05799SMatthew G. Knepley 
80741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
80757cd05799SMatthew G. Knepley @*/
8076d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
8077d71ae5a4SJacob Faibussowitsch {
80787773e69fSMatthew G. Knepley   PetscFunctionBegin;
80797773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80804f572ea9SToby Isaac   PetscAssertPointer(indices, 7);
80819566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
80823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
80837773e69fSMatthew G. Knepley }
80847773e69fSMatthew G. Knepley 
8085e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8086d71ae5a4SJacob Faibussowitsch {
8087552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
8088552f7358SJed Brown   PetscInt          *indices;
808971f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
809071f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
8091552f7358SJed Brown   PetscErrorCode     ierr;
8092552f7358SJed Brown 
8093552f7358SJed Brown   PetscFunctionBegin;
8094552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80959566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
80963dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
80979566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
80983dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
8099e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 5);
8100552f7358SJed Brown 
8101e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
81020d644c17SKarl Rupp 
81039566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
8104d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
81054a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8106552f7358SJed Brown   if (ierr) {
8107552f7358SJed Brown     PetscMPIInt rank;
8108552f7358SJed Brown 
81099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
81109566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
81119566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
81129566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
81139566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8114c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
8115552f7358SJed Brown   }
81164a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
81174a1e0b3eSMatthew G. Knepley     PetscInt i;
81189566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
811963a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
81209566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
81214a1e0b3eSMatthew G. Knepley   }
812271f0bbf9SMatthew G. Knepley 
81239566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
81249566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
81253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81264acb8e1eSToby Isaac }
812771f0bbf9SMatthew G. Knepley 
81284a1e0b3eSMatthew G. Knepley /*@C
8129e8e188d2SZach Atkins   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
8130e8e188d2SZach Atkins 
8131e8e188d2SZach Atkins   Not collective
8132e8e188d2SZach Atkins 
8133e8e188d2SZach Atkins   Input Parameters:
8134e8e188d2SZach Atkins + dm            - The `DM`
8135e8e188d2SZach Atkins . section       - The section describing the layout in `v`, or `NULL` to use the default section
8136e8e188d2SZach Atkins . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
8137e8e188d2SZach Atkins . A             - The matrix
8138e8e188d2SZach Atkins . point         - The point in the `DM`
8139e8e188d2SZach Atkins . values        - The array of values
8140e8e188d2SZach Atkins - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8141e8e188d2SZach Atkins 
8142e8e188d2SZach Atkins   Level: intermediate
8143e8e188d2SZach Atkins 
8144e8e188d2SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8145e8e188d2SZach Atkins @*/
8146e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8147e8e188d2SZach Atkins {
8148e8e188d2SZach Atkins   PetscFunctionBegin;
8149e8e188d2SZach Atkins   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
8150e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
8151e8e188d2SZach Atkins }
8152e8e188d2SZach Atkins 
8153e8e188d2SZach Atkins /*@C
815460225df5SJacob Faibussowitsch   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
81554a1e0b3eSMatthew G. Knepley 
81564a1e0b3eSMatthew G. Knepley   Not collective
81574a1e0b3eSMatthew G. Knepley 
81584a1e0b3eSMatthew G. Knepley   Input Parameters:
8159a1cb98faSBarry Smith + dmRow            - The `DM` for the row fields
816020f4b53cSBarry Smith . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
8161e8e188d2SZach Atkins . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
816220f4b53cSBarry Smith . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
8163a1cb98faSBarry Smith . dmCol            - The `DM` for the column fields
816420f4b53cSBarry Smith . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
8165e8e188d2SZach Atkins . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
816620f4b53cSBarry Smith . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
81674a1e0b3eSMatthew G. Knepley . A                - The matrix
8168a1cb98faSBarry Smith . point            - The point in the `DM`
81694a1e0b3eSMatthew G. Knepley . values           - The array of values
8170a1cb98faSBarry Smith - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
81714a1e0b3eSMatthew G. Knepley 
81724a1e0b3eSMatthew G. Knepley   Level: intermediate
81734a1e0b3eSMatthew G. Knepley 
81741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
81754a1e0b3eSMatthew G. Knepley @*/
8176e8e188d2SZach 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)
8177d71ae5a4SJacob Faibussowitsch {
817871f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
817971f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
818071f0bbf9SMatthew G. Knepley   PetscInt           numIndicesRow, numIndicesCol;
818171f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
818271f0bbf9SMatthew G. Knepley   PetscErrorCode     ierr;
818371f0bbf9SMatthew G. Knepley 
818471f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
818571f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
81869566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
818771f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
81889566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
818971f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
8190e8e188d2SZach Atkins   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5);
81919566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
8192e8e188d2SZach Atkins   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6);
81939566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
8194e8e188d2SZach Atkins   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7);
8195e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 9);
819671f0bbf9SMatthew G. Knepley 
8197e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
8198e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
819971f0bbf9SMatthew G. Knepley 
82009566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
8201d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
82024a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
820371f0bbf9SMatthew G. Knepley   if (ierr) {
820471f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
820571f0bbf9SMatthew G. Knepley 
82069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
82079566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
82089566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
82099566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
82109566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values));
82119566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
8212d3d1a6afSToby Isaac   }
821371f0bbf9SMatthew G. Knepley 
8214e8e188d2SZach Atkins   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
8215e8e188d2SZach Atkins   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
82169566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
82173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8218552f7358SJed Brown }
8219552f7358SJed Brown 
8220d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8221d71ae5a4SJacob Faibussowitsch {
8222de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
8223de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8224de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
8225de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
822617c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8227de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
8228412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
82294ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8230de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
8231de41b84cSMatthew G. Knepley 
8232de41b84cSMatthew G. Knepley   PetscFunctionBegin;
8233de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8234de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
82359566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8236de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
82379566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8238de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
82399566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8240de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
82419566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8242de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8243de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
82449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
824563a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
82469566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
82479566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
8248de41b84cSMatthew G. Knepley   /* Column indices */
82499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
82504ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
8251de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
8252de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
82539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8254de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8255de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8256de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
8257de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
8258de41b84cSMatthew G. Knepley       ++q;
8259de41b84cSMatthew G. Knepley     }
8260de41b84cSMatthew G. Knepley   }
8261de41b84cSMatthew G. Knepley   numCPoints = q;
8262de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8263de41b84cSMatthew G. Knepley     PetscInt fdof;
8264de41b84cSMatthew G. Knepley 
82659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
82664ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8267de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
82689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8269de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
8270de41b84cSMatthew G. Knepley     }
8271de41b84cSMatthew G. Knepley     numCIndices += dof;
8272de41b84cSMatthew G. Knepley   }
8273de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8274de41b84cSMatthew G. Knepley   /* Row indices */
82759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8276412e9a14SMatthew G. Knepley   {
8277012bc364SMatthew G. Knepley     DMPlexTransform tr;
8278012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8279012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8280012bc364SMatthew G. Knepley 
82819566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
82829566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
82839566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8284012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
82859566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8286412e9a14SMatthew G. Knepley   }
82879566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8288de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
8289de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
82909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8291de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
82929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8293de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
8294de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
82959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
82964ca5e9f5SMatthew G. Knepley         if (!dof) continue;
82979371c9d4SSatish Balay         for (s = 0; s < q; ++s)
82989371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
82994ca5e9f5SMatthew G. Knepley         if (s < q) continue;
8300de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
8301de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8302de41b84cSMatthew G. Knepley         ++q;
8303de41b84cSMatthew G. Knepley       }
8304de41b84cSMatthew G. Knepley     }
83059566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8306de41b84cSMatthew G. Knepley   }
8307de41b84cSMatthew G. Knepley   numFPoints = q;
8308de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8309de41b84cSMatthew G. Knepley     PetscInt fdof;
8310de41b84cSMatthew G. Knepley 
83119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
83124ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8313de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
83149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8315de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
8316de41b84cSMatthew G. Knepley     }
8317de41b84cSMatthew G. Knepley     numFIndices += dof;
8318de41b84cSMatthew G. Knepley   }
8319de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8320de41b84cSMatthew G. Knepley 
83211dca8a05SBarry 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);
83221dca8a05SBarry 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);
83239566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
83249566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8325de41b84cSMatthew G. Knepley   if (numFields) {
83264acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
83274acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
83284acb8e1eSToby Isaac 
83294acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
83309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
83319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8332de41b84cSMatthew G. Knepley     }
83334acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
83349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
83359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
83364acb8e1eSToby Isaac     }
83374acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
83389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
83399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
83404acb8e1eSToby Isaac     }
83414acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
83429566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
83439566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8344de41b84cSMatthew G. Knepley     }
8345de41b84cSMatthew G. Knepley   } else {
83464acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
83474acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
83484acb8e1eSToby Isaac 
83499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
83509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
83514acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
83524acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
83534acb8e1eSToby Isaac 
83549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
83559566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8356de41b84cSMatthew G. Knepley     }
83574acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
83584acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
83594acb8e1eSToby Isaac 
83609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
83619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8362de41b84cSMatthew G. Knepley     }
83639566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
83649566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8365de41b84cSMatthew G. Knepley   }
83669566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
83674acb8e1eSToby Isaac   /* TODO: flips */
8368d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8369de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8370de41b84cSMatthew G. Knepley   if (ierr) {
8371de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8372de41b84cSMatthew G. Knepley 
83739566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
83749566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
83759566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
83769566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
83779566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8378de41b84cSMatthew G. Knepley   }
83799566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
83809566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
83819566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
83829566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
83833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8384de41b84cSMatthew G. Knepley }
8385de41b84cSMatthew G. Knepley 
8386d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8387d71ae5a4SJacob Faibussowitsch {
83887c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
83897c927364SMatthew G. Knepley   PetscInt       *cpoints = NULL;
83907c927364SMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
839117c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8392412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
83937c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
83947c927364SMatthew G. Knepley 
83957c927364SMatthew G. Knepley   PetscFunctionBegin;
83967c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
83977c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
83989566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
83997c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
84009566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
84017c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
84029566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
84037c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
84049566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
84057c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
84069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
840763a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
84089566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
84099566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
84107c927364SMatthew G. Knepley   /* Column indices */
84119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
84127c927364SMatthew G. Knepley   maxFPoints = numCPoints;
84137c927364SMatthew G. Knepley   /* Compress out points not in the section */
84147c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
84159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
84167c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
84177c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
84187c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
84197c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
84207c927364SMatthew G. Knepley       ++q;
84217c927364SMatthew G. Knepley     }
84227c927364SMatthew G. Knepley   }
84237c927364SMatthew G. Knepley   numCPoints = q;
84247c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
84257c927364SMatthew G. Knepley     PetscInt fdof;
84267c927364SMatthew G. Knepley 
84279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
84287c927364SMatthew G. Knepley     if (!dof) continue;
84297c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
84309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
84317c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
84327c927364SMatthew G. Knepley     }
84337c927364SMatthew G. Knepley     numCIndices += dof;
84347c927364SMatthew G. Knepley   }
84357c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
84367c927364SMatthew G. Knepley   /* Row indices */
84379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8438412e9a14SMatthew G. Knepley   {
8439012bc364SMatthew G. Knepley     DMPlexTransform tr;
8440012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8441012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8442012bc364SMatthew G. Knepley 
84439566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
84449566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
84459566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8446012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
84479566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8448412e9a14SMatthew G. Knepley   }
84499566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
84507c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
84517c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
84529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
84537c927364SMatthew G. Knepley     /* Compress out points not in the section */
84549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
84557c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
84567c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
84579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
84587c927364SMatthew G. Knepley         if (!dof) continue;
84599371c9d4SSatish Balay         for (s = 0; s < q; ++s)
84609371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
84617c927364SMatthew G. Knepley         if (s < q) continue;
84627c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
84637c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
84647c927364SMatthew G. Knepley         ++q;
84657c927364SMatthew G. Knepley       }
84667c927364SMatthew G. Knepley     }
84679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
84687c927364SMatthew G. Knepley   }
84697c927364SMatthew G. Knepley   numFPoints = q;
84707c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
84717c927364SMatthew G. Knepley     PetscInt fdof;
84727c927364SMatthew G. Knepley 
84739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
84747c927364SMatthew G. Knepley     if (!dof) continue;
84757c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
84769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
84777c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
84787c927364SMatthew G. Knepley     }
84797c927364SMatthew G. Knepley     numFIndices += dof;
84807c927364SMatthew G. Knepley   }
84817c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
84827c927364SMatthew G. Knepley 
84831dca8a05SBarry 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);
84841dca8a05SBarry 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);
84857c927364SMatthew G. Knepley   if (numFields) {
84864acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
84874acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
84884acb8e1eSToby Isaac 
84894acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
84909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
84919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
84927c927364SMatthew G. Knepley     }
84934acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
84949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
84959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
84964acb8e1eSToby Isaac     }
84974acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
84989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
84999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
85004acb8e1eSToby Isaac     }
85014acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
85029566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
85039566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
85047c927364SMatthew G. Knepley     }
85057c927364SMatthew G. Knepley   } else {
85064acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
85074acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
85084acb8e1eSToby Isaac 
85099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
85109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
85114acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
85124acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
85134acb8e1eSToby Isaac 
85149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
85159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
85167c927364SMatthew G. Knepley     }
85174acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
85184acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
85194acb8e1eSToby Isaac 
85209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
85219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
85227c927364SMatthew G. Knepley     }
85239566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
85249566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
85257c927364SMatthew G. Knepley   }
85269566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
85279566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
85283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85297c927364SMatthew G. Knepley }
85307c927364SMatthew G. Knepley 
85317cd05799SMatthew G. Knepley /*@C
85327cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
85337cd05799SMatthew G. Knepley 
85347cd05799SMatthew G. Knepley   Input Parameter:
8535a1cb98faSBarry Smith . dm - The `DMPLEX` object
85367cd05799SMatthew G. Knepley 
85377cd05799SMatthew G. Knepley   Output Parameter:
85387cd05799SMatthew G. Knepley . cellHeight - The height of a cell
85397cd05799SMatthew G. Knepley 
85407cd05799SMatthew G. Knepley   Level: developer
85417cd05799SMatthew G. Knepley 
85421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
85437cd05799SMatthew G. Knepley @*/
8544d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8545d71ae5a4SJacob Faibussowitsch {
8546552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8547552f7358SJed Brown 
8548552f7358SJed Brown   PetscFunctionBegin;
8549552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
85504f572ea9SToby Isaac   PetscAssertPointer(cellHeight, 2);
8551552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
85523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8553552f7358SJed Brown }
8554552f7358SJed Brown 
85557cd05799SMatthew G. Knepley /*@C
85567cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
85577cd05799SMatthew G. Knepley 
85587cd05799SMatthew G. Knepley   Input Parameters:
8559a1cb98faSBarry Smith + dm         - The `DMPLEX` object
85607cd05799SMatthew G. Knepley - cellHeight - The height of a cell
85617cd05799SMatthew G. Knepley 
85627cd05799SMatthew G. Knepley   Level: developer
85637cd05799SMatthew G. Knepley 
85641cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
85657cd05799SMatthew G. Knepley @*/
8566d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8567d71ae5a4SJacob Faibussowitsch {
8568552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8569552f7358SJed Brown 
8570552f7358SJed Brown   PetscFunctionBegin;
8571552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8572552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
85733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8574552f7358SJed Brown }
8575552f7358SJed Brown 
8576e6139122SMatthew G. Knepley /*@
85772827ebadSStefano Zampini   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8578e6139122SMatthew G. Knepley 
85792827ebadSStefano Zampini   Input Parameters:
85802827ebadSStefano Zampini + dm - The `DMPLEX` object
85812827ebadSStefano Zampini - ct - The `DMPolytopeType` of the cell
8582e6139122SMatthew G. Knepley 
8583e6139122SMatthew G. Knepley   Output Parameters:
85842827ebadSStefano Zampini + start - The first cell of this type, or `NULL`
85852827ebadSStefano Zampini - end   - The upper bound on this celltype, or `NULL`
8586e6139122SMatthew G. Knepley 
85872a9f31c0SMatthew G. Knepley   Level: advanced
8588e6139122SMatthew G. Knepley 
85892827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8590e6139122SMatthew G. Knepley @*/
85912827ebadSStefano Zampini PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end)
8592d71ae5a4SJacob Faibussowitsch {
85932827ebadSStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
85942827ebadSStefano Zampini   DMLabel  label;
85952827ebadSStefano Zampini   PetscInt pStart, pEnd;
8596e6139122SMatthew G. Knepley 
8597e6139122SMatthew G. Knepley   PetscFunctionBegin;
8598e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
85992827ebadSStefano Zampini   if (start) {
86004f572ea9SToby Isaac     PetscAssertPointer(start, 3);
86012827ebadSStefano Zampini     *start = 0;
86022827ebadSStefano Zampini   }
86032827ebadSStefano Zampini   if (end) {
86044f572ea9SToby Isaac     PetscAssertPointer(end, 4);
86052827ebadSStefano Zampini     *end = 0;
86062827ebadSStefano Zampini   }
86072827ebadSStefano Zampini   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
86082827ebadSStefano Zampini   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
86092827ebadSStefano Zampini   if (mesh->tr) {
86102827ebadSStefano Zampini     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
86112827ebadSStefano Zampini   } else {
86122827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
86132827ebadSStefano Zampini     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
86142827ebadSStefano Zampini     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
86152827ebadSStefano Zampini   }
86163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8617e6139122SMatthew G. Knepley }
8618e6139122SMatthew G. Knepley 
8619d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8620d71ae5a4SJacob Faibussowitsch {
8621552f7358SJed Brown   PetscSection section, globalSection;
8622552f7358SJed Brown   PetscInt    *numbers, p;
8623552f7358SJed Brown 
8624552f7358SJed Brown   PetscFunctionBegin;
8625d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
86269566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
86279566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
862848a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
86299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
86309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
86319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8632552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
86339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8634ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
8635ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
8636552f7358SJed Brown   }
86379566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8638ef48cebcSMatthew G. Knepley   if (globalSize) {
8639ef48cebcSMatthew G. Knepley     PetscLayout layout;
86409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
86419566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
86429566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8643ef48cebcSMatthew G. Knepley   }
86449566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
86459566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
86463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8647552f7358SJed Brown }
8648552f7358SJed Brown 
8649d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8650d71ae5a4SJacob Faibussowitsch {
8651412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
8652552f7358SJed Brown 
8653552f7358SJed Brown   PetscFunctionBegin;
86549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
86559566063dSJacob Faibussowitsch   if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
86569566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
86579566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
86583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8659552f7358SJed Brown }
866081ed3555SMatthew G. Knepley 
86618dab3259SMatthew G. Knepley /*@
86627cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
86637cd05799SMatthew G. Knepley 
86647cd05799SMatthew G. Knepley   Input Parameter:
8665a1cb98faSBarry Smith . dm - The `DMPLEX` object
86667cd05799SMatthew G. Knepley 
86677cd05799SMatthew G. Knepley   Output Parameter:
86687cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
86697cd05799SMatthew G. Knepley 
86707cd05799SMatthew G. Knepley   Level: developer
86717cd05799SMatthew G. Knepley 
86721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()`
86737cd05799SMatthew G. Knepley @*/
8674d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8675d71ae5a4SJacob Faibussowitsch {
867681ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
867781ed3555SMatthew G. Knepley 
867881ed3555SMatthew G. Knepley   PetscFunctionBegin;
867981ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86809566063dSJacob Faibussowitsch   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8681552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
86823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8683552f7358SJed Brown }
8684552f7358SJed Brown 
8685d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8686d71ae5a4SJacob Faibussowitsch {
8687412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
868881ed3555SMatthew G. Knepley 
868981ed3555SMatthew G. Knepley   PetscFunctionBegin;
869081ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
86929566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
86933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
869481ed3555SMatthew G. Knepley }
869581ed3555SMatthew G. Knepley 
86968dab3259SMatthew G. Knepley /*@
86976aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
86987cd05799SMatthew G. Knepley 
86997cd05799SMatthew G. Knepley   Input Parameter:
8700a1cb98faSBarry Smith . dm - The `DMPLEX` object
87017cd05799SMatthew G. Knepley 
87027cd05799SMatthew G. Knepley   Output Parameter:
87037cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
87047cd05799SMatthew G. Knepley 
87057cd05799SMatthew G. Knepley   Level: developer
87067cd05799SMatthew G. Knepley 
87071cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
87087cd05799SMatthew G. Knepley @*/
8709d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8710d71ae5a4SJacob Faibussowitsch {
8711552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8712552f7358SJed Brown 
8713552f7358SJed Brown   PetscFunctionBegin;
8714552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87159566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8716552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
87173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8718552f7358SJed Brown }
8719552f7358SJed Brown 
87208dab3259SMatthew G. Knepley /*@
8721966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
8722966484cfSJed Brown 
872320f4b53cSBarry Smith   Collective
87247cd05799SMatthew G. Knepley 
87257cd05799SMatthew G. Knepley   Input Parameter:
8726a1cb98faSBarry Smith . dm - The `DMPLEX` object
87277cd05799SMatthew G. Knepley 
87287cd05799SMatthew G. Knepley   Output Parameter:
87297cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
87307cd05799SMatthew G. Knepley 
8731a1cb98faSBarry Smith   Level: developer
8732966484cfSJed Brown 
8733a1cb98faSBarry Smith   Notes:
8734a1cb98faSBarry Smith   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
8735966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
8736966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
8737966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
8738966484cfSJed Brown 
8739966484cfSJed Brown   The partitioned mesh is
8740966484cfSJed Brown   ```
8741966484cfSJed Brown   (2)--0--(3)--1--(4)    (1)--0--(2)
8742966484cfSJed Brown   ```
8743966484cfSJed Brown   and its global numbering is
8744966484cfSJed Brown   ```
8745966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
8746966484cfSJed Brown   ```
8747966484cfSJed Brown   Then the global numbering is provided as
8748966484cfSJed Brown   ```
8749966484cfSJed Brown   [0] Number of indices in set 5
8750966484cfSJed Brown   [0] 0 0
8751966484cfSJed Brown   [0] 1 1
8752966484cfSJed Brown   [0] 2 3
8753966484cfSJed Brown   [0] 3 4
8754966484cfSJed Brown   [0] 4 -6
8755966484cfSJed Brown   [1] Number of indices in set 3
8756966484cfSJed Brown   [1] 0 2
8757966484cfSJed Brown   [1] 1 5
8758966484cfSJed Brown   [1] 2 6
8759966484cfSJed Brown   ```
8760966484cfSJed Brown 
87611cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
87627cd05799SMatthew G. Knepley @*/
8763d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8764d71ae5a4SJacob Faibussowitsch {
8765ef48cebcSMatthew G. Knepley   IS        nums[4];
8766862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
8767ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
87680c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
8769ef48cebcSMatthew G. Knepley 
8770ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8771ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
87730c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
87749566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
87750c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
8776862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8777862913ffSStefano Zampini     PetscInt end;
8778862913ffSStefano Zampini 
8779862913ffSStefano Zampini     depths[d] = depth - d;
87809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
87810c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
8782862913ffSStefano Zampini   }
87830c15888dSMatthew G. Knepley   if (empty)
87840c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
87850c15888dSMatthew G. Knepley       depths[d] = -1;
87860c15888dSMatthew G. Knepley       starts[d] = -1;
87870c15888dSMatthew G. Knepley     }
87880c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
87891c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
8790ad540459SPierre 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]);
87910c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
8792ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8793ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8794ef48cebcSMatthew G. Knepley 
87959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
87969566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8797ef48cebcSMatthew G. Knepley     shift += gsize;
8798ef48cebcSMatthew G. Knepley   }
8799d1c35871SJed Brown   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
88009566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
88013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8802ef48cebcSMatthew G. Knepley }
8803ef48cebcSMatthew G. Knepley 
880408a22f4bSMatthew G. Knepley /*@
880508a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
880608a22f4bSMatthew G. Knepley 
880708a22f4bSMatthew G. Knepley   Input Parameter:
8808a1cb98faSBarry Smith . dm - The `DMPLEX` object
880908a22f4bSMatthew G. Knepley 
881008a22f4bSMatthew G. Knepley   Output Parameter:
881108a22f4bSMatthew G. Knepley . ranks - The rank field
881208a22f4bSMatthew G. Knepley 
8813a1cb98faSBarry Smith   Options Database Key:
881420f4b53cSBarry Smith . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
881508a22f4bSMatthew G. Knepley 
881608a22f4bSMatthew G. Knepley   Level: intermediate
881708a22f4bSMatthew G. Knepley 
88181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
881908a22f4bSMatthew G. Knepley @*/
8820d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8821d71ae5a4SJacob Faibussowitsch {
882208a22f4bSMatthew G. Knepley   DM             rdm;
882308a22f4bSMatthew G. Knepley   PetscFE        fe;
882408a22f4bSMatthew G. Knepley   PetscScalar   *r;
882508a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
8826a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
882708a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
8828a55f9a55SMatthew G. Knepley   PetscBool      simplex;
882908a22f4bSMatthew G. Knepley 
883008a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
8831f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88324f572ea9SToby Isaac   PetscAssertPointer(ranks, 2);
88339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
88349566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
88359566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
88369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
88379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8838a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
88399566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
88409566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
88419566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
88429566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
88439566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
88449566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
88459566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
88469566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
884708a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
884808a22f4bSMatthew G. Knepley     PetscScalar *lr;
884908a22f4bSMatthew G. Knepley 
88509566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
885171f09efeSPierre Jolivet     if (lr) *lr = rank;
885208a22f4bSMatthew G. Knepley   }
88539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
88549566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
88553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
885608a22f4bSMatthew G. Knepley }
885708a22f4bSMatthew G. Knepley 
8858ca8062c8SMatthew G. Knepley /*@
885918e14f0cSMatthew G. Knepley   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
886018e14f0cSMatthew G. Knepley 
886118e14f0cSMatthew G. Knepley   Input Parameters:
886220f4b53cSBarry Smith + dm    - The `DMPLEX`
886320f4b53cSBarry Smith - label - The `DMLabel`
886418e14f0cSMatthew G. Knepley 
886518e14f0cSMatthew G. Knepley   Output Parameter:
886618e14f0cSMatthew G. Knepley . val - The label value field
886718e14f0cSMatthew G. Knepley 
886820f4b53cSBarry Smith   Options Database Key:
886920f4b53cSBarry Smith . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
887018e14f0cSMatthew G. Knepley 
887118e14f0cSMatthew G. Knepley   Level: intermediate
887218e14f0cSMatthew G. Knepley 
88731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
887418e14f0cSMatthew G. Knepley @*/
8875d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8876d71ae5a4SJacob Faibussowitsch {
887718e14f0cSMatthew G. Knepley   DM           rdm;
887818e14f0cSMatthew G. Knepley   PetscFE      fe;
887918e14f0cSMatthew G. Knepley   PetscScalar *v;
888018e14f0cSMatthew G. Knepley   PetscInt     dim, cStart, cEnd, c;
888118e14f0cSMatthew G. Knepley 
888218e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
888318e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88844f572ea9SToby Isaac   PetscAssertPointer(label, 2);
88854f572ea9SToby Isaac   PetscAssertPointer(val, 3);
88869566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
88879566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
88889566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
88899566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "label_value"));
88909566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
88919566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
88929566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
88939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
88949566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
88959566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*val, "label_value"));
88969566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*val, &v));
889718e14f0cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
889818e14f0cSMatthew G. Knepley     PetscScalar *lv;
889918e14f0cSMatthew G. Knepley     PetscInt     cval;
890018e14f0cSMatthew G. Knepley 
89019566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv));
89029566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, c, &cval));
890318e14f0cSMatthew G. Knepley     *lv = cval;
890418e14f0cSMatthew G. Knepley   }
89059566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*val, &v));
89069566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
89073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
890818e14f0cSMatthew G. Knepley }
890918e14f0cSMatthew G. Knepley 
891018e14f0cSMatthew G. Knepley /*@
8911ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8912ca8062c8SMatthew G. Knepley 
891369916449SMatthew G. Knepley   Input Parameter:
8914a1cb98faSBarry Smith . dm - The `DMPLEX` object
8915a1cb98faSBarry Smith 
8916a1cb98faSBarry Smith   Level: developer
8917ca8062c8SMatthew G. Knepley 
891895eb5ee5SVaclav Hapla   Notes:
891995eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
892095eb5ee5SVaclav Hapla 
892120f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
8922ca8062c8SMatthew G. Knepley 
89231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
8924ca8062c8SMatthew G. Knepley @*/
8925d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
8926d71ae5a4SJacob Faibussowitsch {
8927ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
8928ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
8929ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
893057beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
893157beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
8932ca8062c8SMatthew G. Knepley 
8933ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
8934ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89359566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
89369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
89379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
8938ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
89399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8940ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
89419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
89429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
8943ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
894442e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
894542e66dfaSMatthew G. Knepley       PetscInt  d;
894642e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
89479371c9d4SSatish Balay         if (cone[c] == cone[d]) {
89489371c9d4SSatish Balay           dup = PETSC_TRUE;
89499371c9d4SSatish Balay           break;
89509371c9d4SSatish Balay         }
895142e66dfaSMatthew G. Knepley       }
89529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
89539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
8954ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
8955ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
8956ca8062c8SMatthew G. Knepley       }
895742e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
895863a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
895948a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
89609566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
896163a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
896248a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
89639566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
896463a3b9bcSJacob 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]);
8965f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
8966ca8062c8SMatthew G. Knepley       }
896742e66dfaSMatthew G. Knepley     }
89689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
89699371c9d4SSatish Balay     if (p != pp) {
89709371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
89719371c9d4SSatish Balay       continue;
89729371c9d4SSatish Balay     }
89739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
89749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
8975ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
89769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
89779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
8978ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
89799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
89809371c9d4SSatish Balay         if (cone[c] != pp) {
89819371c9d4SSatish Balay           c = 0;
89829371c9d4SSatish Balay           break;
89839371c9d4SSatish Balay         }
8984ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
8985ca8062c8SMatthew G. Knepley       }
8986ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
898763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
898848a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
89899566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
899063a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
899148a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
89929566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
899363a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
8994ca8062c8SMatthew G. Knepley       }
8995ca8062c8SMatthew G. Knepley     }
8996ca8062c8SMatthew G. Knepley   }
899757beb4faSStefano Zampini   if (storagecheck) {
89989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
89999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
900063a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
900157beb4faSStefano Zampini   }
90023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9003ca8062c8SMatthew G. Knepley }
9004ca8062c8SMatthew G. Knepley 
9005412e9a14SMatthew G. Knepley /*
9006412e9a14SMatthew 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.
9007412e9a14SMatthew G. Knepley */
9008d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
9009d71ae5a4SJacob Faibussowitsch {
9010412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
9011412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
9012412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
9013412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
9014412e9a14SMatthew G. Knepley 
9015412e9a14SMatthew G. Knepley   PetscFunctionBegin;
9016412e9a14SMatthew G. Knepley   *unsplit = 0;
9017412e9a14SMatthew G. Knepley   switch (ct) {
9018d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
9019d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
9020d71ae5a4SJacob Faibussowitsch     break;
9021412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
90229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
90239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9024412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
90259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
9026412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
9027412e9a14SMatthew G. Knepley     }
9028412e9a14SMatthew G. Knepley     break;
9029412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
9030412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
90319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
90329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9033412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
90349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
90359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
9036412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
90379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
9038412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
9039412e9a14SMatthew G. Knepley           PetscInt p;
90409371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
90419371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
9042412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
9043412e9a14SMatthew G. Knepley         }
9044412e9a14SMatthew G. Knepley       }
9045412e9a14SMatthew G. Knepley     }
9046412e9a14SMatthew G. Knepley     break;
9047d71ae5a4SJacob Faibussowitsch   default:
9048d71ae5a4SJacob Faibussowitsch     break;
9049412e9a14SMatthew G. Knepley   }
9050412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
90519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
9052412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
9053412e9a14SMatthew G. Knepley   }
90543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9055412e9a14SMatthew G. Knepley }
9056412e9a14SMatthew G. Knepley 
9057ca8062c8SMatthew G. Knepley /*@
9058ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
9059ca8062c8SMatthew G. Knepley 
9060ca8062c8SMatthew G. Knepley   Input Parameters:
9061a1cb98faSBarry Smith + dm         - The `DMPLEX` object
906258723a97SMatthew G. Knepley - cellHeight - Normally 0
9063ca8062c8SMatthew G. Knepley 
9064a1cb98faSBarry Smith   Level: developer
9065a1cb98faSBarry Smith 
906695eb5ee5SVaclav Hapla   Notes:
906795eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
906825c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
9069ca8062c8SMatthew G. Knepley 
907020f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
907195eb5ee5SVaclav Hapla 
90721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9073ca8062c8SMatthew G. Knepley @*/
9074d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
9075d71ae5a4SJacob Faibussowitsch {
9076412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
9077412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
9078412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
9079ca8062c8SMatthew G. Knepley 
9080ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9081ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90829566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
90839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
90849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9085412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9086412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
9087412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
908858723a97SMatthew G. Knepley 
90899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
909063a3b9bcSJacob Faibussowitsch     PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c);
9091412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
9092412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
90939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
909463a3b9bcSJacob 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));
9095412e9a14SMatthew G. Knepley     }
90969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
909758723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
909858723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
9099412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
910058723a97SMatthew G. Knepley     }
91019566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9102412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
9103412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
9104412e9a14SMatthew G. Knepley       PetscInt unsplit;
910542363296SMatthew G. Knepley 
91069566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9107412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
910842363296SMatthew G. Knepley     }
910963a3b9bcSJacob 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));
911042363296SMatthew G. Knepley   }
91113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9112ca8062c8SMatthew G. Knepley }
91139bf0dad6SMatthew G. Knepley 
91149bf0dad6SMatthew G. Knepley /*@
91159bf0dad6SMatthew 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
91169bf0dad6SMatthew G. Knepley 
911720f4b53cSBarry Smith   Collective
9118899ea2b8SJacob Faibussowitsch 
91199bf0dad6SMatthew G. Knepley   Input Parameters:
9120a1cb98faSBarry Smith + dm         - The `DMPLEX` object
91219bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
91229bf0dad6SMatthew G. Knepley 
9123a1cb98faSBarry Smith   Level: developer
9124a1cb98faSBarry Smith 
912545da879fSVaclav Hapla   Notes:
912645da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
912745da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
912845da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
912945da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
91309bf0dad6SMatthew G. Knepley 
9131a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
913295eb5ee5SVaclav Hapla 
91331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
91349bf0dad6SMatthew G. Knepley @*/
9135d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
9136d71ae5a4SJacob Faibussowitsch {
9137ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
9138899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
91399bf0dad6SMatthew G. Knepley 
91409bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
91419bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91428f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
91433ba16761SJacob Faibussowitsch   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
91448f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
91453ba16761SJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
91463ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
9147899ea2b8SJacob Faibussowitsch   }
9148899ea2b8SJacob Faibussowitsch 
91499566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
91509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
91519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9152ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
91539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
91543554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
9155412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
9156412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
9157ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
9158412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
9159412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
91609bf0dad6SMatthew G. Knepley 
91619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
91629566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9163412e9a14SMatthew G. Knepley       if (unsplit) continue;
91649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
91659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
91669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
91679566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
91689bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
91699bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
91709bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
91719bf0dad6SMatthew G. Knepley       }
91729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
917363a3b9bcSJacob 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);
91749bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
9175d4961f80SStefano Zampini         DMPolytopeType fct;
91769bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
91779bf0dad6SMatthew G. Knepley 
91789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
91799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
91809bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
91819bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
91829bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
91839bf0dad6SMatthew G. Knepley         }
918463a3b9bcSJacob 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]);
91859bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
9186b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
9187b5a892a1SMatthew G. Knepley             PetscInt v1;
9188b5a892a1SMatthew G. Knepley 
91899566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
919063a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
91919566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
919263a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
91939566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
919463a3b9bcSJacob 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]);
9195b5a892a1SMatthew G. Knepley           }
91969bf0dad6SMatthew G. Knepley         }
91979566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
9198412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
91999bf0dad6SMatthew G. Knepley       }
92009566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
92019566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
92029bf0dad6SMatthew G. Knepley     }
92033554e41dSMatthew G. Knepley   }
92043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9205552f7358SJed Brown }
92063913d7c8SMatthew G. Knepley 
9207bb6a34a8SMatthew G. Knepley /*@
9208bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
9209bb6a34a8SMatthew G. Knepley 
9210bb6a34a8SMatthew G. Knepley   Input Parameter:
9211a1cb98faSBarry Smith . dm - The `DMPLEX` object
9212a1cb98faSBarry Smith 
9213a1cb98faSBarry Smith   Level: developer
9214bb6a34a8SMatthew G. Knepley 
921595eb5ee5SVaclav Hapla   Notes:
921695eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
921795eb5ee5SVaclav Hapla 
921820f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9219bb6a34a8SMatthew G. Knepley 
92201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9221bb6a34a8SMatthew G. Knepley @*/
9222d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
9223d71ae5a4SJacob Faibussowitsch {
9224a2a9e04cSMatthew G. Knepley   Vec       coordinates;
9225bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
9226bb6a34a8SMatthew G. Knepley   PetscReal vol;
922751a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9228bb6a34a8SMatthew G. Knepley 
9229bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
92309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
92319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
92323ba16761SJacob Faibussowitsch   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
92339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
9234bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
92359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9236a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
92379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
92383ba16761SJacob Faibussowitsch   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9239412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9240412e9a14SMatthew G. Knepley     DMPolytopeType ct;
9241412e9a14SMatthew G. Knepley     PetscInt       unsplit;
9242412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
9243412e9a14SMatthew G. Knepley 
92449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9245412e9a14SMatthew G. Knepley     switch (ct) {
9246412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9247412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9248d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9249d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
9250d71ae5a4SJacob Faibussowitsch       break;
9251d71ae5a4SJacob Faibussowitsch     default:
9252d71ae5a4SJacob Faibussowitsch       break;
9253412e9a14SMatthew G. Knepley     }
9254412e9a14SMatthew G. Knepley     switch (ct) {
9255412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
9256412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9257412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9258d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
9259d71ae5a4SJacob Faibussowitsch       continue;
9260d71ae5a4SJacob Faibussowitsch     default:
9261d71ae5a4SJacob Faibussowitsch       break;
9262412e9a14SMatthew G. Knepley     }
92639566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9264412e9a14SMatthew G. Knepley     if (unsplit) continue;
92659566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
92661dca8a05SBarry 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);
926763a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
92686858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
92696858538eSMatthew G. Knepley     if (depth > 1) {
92709566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
92711dca8a05SBarry 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);
927263a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9273bb6a34a8SMatthew G. Knepley     }
9274bb6a34a8SMatthew G. Knepley   }
92753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9276bb6a34a8SMatthew G. Knepley }
9277bb6a34a8SMatthew G. Knepley 
927803da9461SVaclav Hapla /*@
927920f4b53cSBarry Smith   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
92807726db96SVaclav Hapla 
928120f4b53cSBarry Smith   Collective
928203da9461SVaclav Hapla 
928303da9461SVaclav Hapla   Input Parameters:
9284a1cb98faSBarry Smith + dm              - The `DMPLEX` object
928520f4b53cSBarry Smith . pointSF         - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9286a1cb98faSBarry Smith - allowExtraRoots - Flag to allow extra points not present in the `DM`
9287a1cb98faSBarry Smith 
9288a1cb98faSBarry Smith   Level: developer
928903da9461SVaclav Hapla 
9290e83a0d2dSVaclav Hapla   Notes:
9291e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
929203da9461SVaclav Hapla 
9293a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
929495eb5ee5SVaclav Hapla 
9295baca6076SPierre Jolivet   Extra roots can come from periodic cuts, where additional points appear on the boundary
9296d7d32a9aSMatthew G. Knepley 
92971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
929803da9461SVaclav Hapla @*/
9299d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9300d71ae5a4SJacob Faibussowitsch {
93017726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
93027726db96SVaclav Hapla   const PetscInt    *locals;
93037726db96SVaclav Hapla   const PetscSFNode *remotes;
9304f0cfc026SVaclav Hapla   PetscBool          distributed;
93057726db96SVaclav Hapla   MPI_Comm           comm;
93067726db96SVaclav Hapla   PetscMPIInt        rank;
930703da9461SVaclav Hapla 
930803da9461SVaclav Hapla   PetscFunctionBegin;
930903da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93107726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
93117726db96SVaclav Hapla   else pointSF = dm->sf;
93127726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
93137726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
93147726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
93157726db96SVaclav Hapla   {
93167726db96SVaclav Hapla     PetscMPIInt mpiFlag;
93177726db96SVaclav Hapla 
93187726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
93197726db96SVaclav 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);
93207726db96SVaclav Hapla   }
93217726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
93229566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
93237726db96SVaclav Hapla   if (!distributed) {
93247726db96SVaclav 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);
93253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
93268918e3e2SVaclav Hapla   }
93277726db96SVaclav 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);
93287726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
932903da9461SVaclav Hapla 
93307726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
93317726db96SVaclav Hapla   {
93327726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
93337726db96SVaclav Hapla 
93347726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
93357726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9336d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
93377726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
93387726db96SVaclav Hapla   }
93397726db96SVaclav Hapla 
93407726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
93417726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
93427726db96SVaclav Hapla     PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index);
93437726db96SVaclav Hapla   }
93447726db96SVaclav Hapla 
93457726db96SVaclav Hapla   /* Check there are no cells in interface */
93467726db96SVaclav Hapla   if (!overlap) {
93477726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
93487726db96SVaclav Hapla 
93499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
93509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9351f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
93527726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
9353f5869d18SMatthew G. Knepley 
93547726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
93557726db96SVaclav Hapla     }
935603da9461SVaclav Hapla   }
9357ece87651SVaclav Hapla 
93587726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
93597726db96SVaclav Hapla   {
93607726db96SVaclav Hapla     const PetscInt *rootdegree;
93617726db96SVaclav Hapla 
93627726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
93637726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9364f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
93657726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9366f5869d18SMatthew G. Knepley       const PetscInt *cone;
9367f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9368f5869d18SMatthew G. Knepley 
93699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
93709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9371f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9372f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
93737726db96SVaclav Hapla           if (locals) {
93749566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
93757726db96SVaclav Hapla           } else {
93767726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
93777726db96SVaclav Hapla           }
937863a3b9bcSJacob 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]);
9379f5869d18SMatthew G. Knepley         }
9380f5869d18SMatthew G. Knepley       }
9381ece87651SVaclav Hapla     }
93827726db96SVaclav Hapla   }
93833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
938403da9461SVaclav Hapla }
938503da9461SVaclav Hapla 
93867f9d8d6cSVaclav Hapla /*@
938720f4b53cSBarry Smith   DMPlexCheck - Perform various checks of `DMPLEX` sanity
93887f9d8d6cSVaclav Hapla 
93897f9d8d6cSVaclav Hapla   Input Parameter:
9390a1cb98faSBarry Smith . dm - The `DMPLEX` object
9391a1cb98faSBarry Smith 
9392a1cb98faSBarry Smith   Level: developer
93937f9d8d6cSVaclav Hapla 
93947f9d8d6cSVaclav Hapla   Notes:
93957f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
93967f9d8d6cSVaclav Hapla 
939720f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
93987f9d8d6cSVaclav Hapla 
939920f4b53cSBarry Smith   Currently does not include `DMPlexCheckCellShape()`.
94007f9d8d6cSVaclav Hapla 
94011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
94027f9d8d6cSVaclav Hapla @*/
9403d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9404d71ae5a4SJacob Faibussowitsch {
94057f9d8d6cSVaclav Hapla   PetscInt cellHeight;
94067f9d8d6cSVaclav Hapla 
9407b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
94087f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
94099566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
94109566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
94119566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
94129566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9413d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
94149566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
94153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9416b5a892a1SMatthew G. Knepley }
9417b5a892a1SMatthew G. Knepley 
94189371c9d4SSatish Balay typedef struct cell_stats {
9419068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9420068a5610SStefano Zampini   PetscInt  count;
9421068a5610SStefano Zampini } cell_stats_t;
9422068a5610SStefano Zampini 
9423d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9424d71ae5a4SJacob Faibussowitsch {
9425068a5610SStefano Zampini   PetscInt i, N = *len;
9426068a5610SStefano Zampini 
9427068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9428068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9429068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9430068a5610SStefano Zampini 
9431068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9432068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9433068a5610SStefano Zampini     B->sum += A->sum;
9434068a5610SStefano Zampini     B->squaresum += A->squaresum;
9435068a5610SStefano Zampini     B->count += A->count;
9436068a5610SStefano Zampini   }
9437068a5610SStefano Zampini }
9438068a5610SStefano Zampini 
9439068a5610SStefano Zampini /*@
944043fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9441068a5610SStefano Zampini 
944220f4b53cSBarry Smith   Collective
94438261a58bSMatthew G. Knepley 
9444068a5610SStefano Zampini   Input Parameters:
9445a1cb98faSBarry Smith + dm        - The `DMPLEX` object
944620f4b53cSBarry Smith . output    - If true, statistics will be displayed on `stdout`
9447a1cb98faSBarry Smith - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9448a1cb98faSBarry Smith 
9449a1cb98faSBarry Smith   Level: developer
9450068a5610SStefano Zampini 
945195eb5ee5SVaclav Hapla   Notes:
945295eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
945395eb5ee5SVaclav Hapla 
9454a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9455068a5610SStefano Zampini 
94561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9457068a5610SStefano Zampini @*/
9458d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9459d71ae5a4SJacob Faibussowitsch {
9460068a5610SStefano Zampini   DM           dmCoarse;
946143fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
946243fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
946343fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
946443fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9465412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
946643fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9467068a5610SStefano Zampini 
9468068a5610SStefano Zampini   PetscFunctionBegin;
9469068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9470068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9471068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9472068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9473068a5610SStefano Zampini   stats.count                 = 0;
9474068a5610SStefano Zampini 
94759566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
94769566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
94779566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
94789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
94799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
94809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9481412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9482068a5610SStefano Zampini     PetscInt  i;
9483068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9484068a5610SStefano Zampini 
94859566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
948663a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
948743fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9488068a5610SStefano Zampini       frobJ += J[i] * J[i];
9489068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9490068a5610SStefano Zampini     }
9491068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9492068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9493068a5610SStefano Zampini 
9494068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9495068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9496068a5610SStefano Zampini     stats.sum += cond;
9497068a5610SStefano Zampini     stats.squaresum += cond2;
9498068a5610SStefano Zampini     stats.count++;
94998261a58bSMatthew G. Knepley     if (output && cond > limit) {
950043fa8764SMatthew G. Knepley       PetscSection coordSection;
950143fa8764SMatthew G. Knepley       Vec          coordsLocal;
950243fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
950343fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
950443fa8764SMatthew G. Knepley 
95059566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
95069566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
95079566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
950863a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
950943fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
951063a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
951143fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
95129566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
95139566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
951443fa8764SMatthew G. Knepley         }
95159566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
951643fa8764SMatthew G. Knepley       }
95179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
951843fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
951943fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
952043fa8764SMatthew G. Knepley 
952143fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
952243fa8764SMatthew G. Knepley           PetscReal len;
952343fa8764SMatthew G. Knepley 
95249566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
952563a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
952643fa8764SMatthew G. Knepley         }
952743fa8764SMatthew G. Knepley       }
95289566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
95299566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
953043fa8764SMatthew G. Knepley     }
9531068a5610SStefano Zampini   }
95329566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9533068a5610SStefano Zampini 
9534068a5610SStefano Zampini   if (size > 1) {
9535068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9536068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9537068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9538068a5610SStefano Zampini     MPI_Op       statReduce;
9539068a5610SStefano Zampini 
95409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
95419566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
95429566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
95439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
95449566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
95459566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
9546068a5610SStefano Zampini   } else {
95479566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
9548068a5610SStefano Zampini   }
9549dd400576SPatrick Sanan   if (rank == 0) {
9550068a5610SStefano Zampini     count = globalStats.count;
9551068a5610SStefano Zampini     min   = globalStats.min;
9552068a5610SStefano Zampini     max   = globalStats.max;
9553068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
9554068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
9555068a5610SStefano Zampini   }
9556068a5610SStefano Zampini 
955748a46eb9SPierre 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));
95589566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
9559068a5610SStefano Zampini 
95609566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
9561068a5610SStefano Zampini   if (dmCoarse) {
9562068a5610SStefano Zampini     PetscBool isplex;
9563068a5610SStefano Zampini 
95649566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
95651baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
9566068a5610SStefano Zampini   }
95673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9568068a5610SStefano Zampini }
9569068a5610SStefano Zampini 
9570f108dbd7SJacob Faibussowitsch /*@
9571f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
9572f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
9573f108dbd7SJacob Faibussowitsch 
957420f4b53cSBarry Smith   Collective
9575f108dbd7SJacob Faibussowitsch 
9576f108dbd7SJacob Faibussowitsch   Input Parameters:
9577a1cb98faSBarry Smith + dm   - The `DMPLEX` object
9578a1cb98faSBarry Smith . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
9579f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
9580f108dbd7SJacob Faibussowitsch 
9581f108dbd7SJacob Faibussowitsch   Output Parameters:
958220f4b53cSBarry Smith + OrthQual      - `Vec` containing orthogonal quality per cell
9583a1cb98faSBarry Smith - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
9584f108dbd7SJacob Faibussowitsch 
9585f108dbd7SJacob Faibussowitsch   Options Database Keys:
9586a1cb98faSBarry Smith + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
9587f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view   - view OrthQual vector.
9588f108dbd7SJacob Faibussowitsch 
9589a1cb98faSBarry Smith   Level: intermediate
9590a1cb98faSBarry Smith 
9591f108dbd7SJacob Faibussowitsch   Notes:
9592a4e35b19SJacob Faibussowitsch   Orthogonal quality is given by the following formula\:
9593f108dbd7SJacob Faibussowitsch 
9594a1cb98faSBarry Smith   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
9595f108dbd7SJacob Faibussowitsch 
9596f108dbd7SJacob 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
9597f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
9598f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
9599f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
9600f108dbd7SJacob Faibussowitsch 
9601f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
9602f108dbd7SJacob Faibussowitsch 
9603a1cb98faSBarry Smith   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
9604f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
9605f108dbd7SJacob Faibussowitsch 
9606f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
9607f108dbd7SJacob Faibussowitsch 
96081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
9609f108dbd7SJacob Faibussowitsch @*/
9610d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
9611d71ae5a4SJacob Faibussowitsch {
96126ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
96136ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
96146ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
9615f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
96166ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
9617f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
9618f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
9619f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
9620f108dbd7SJacob Faibussowitsch   IS                     glob;
9621f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
9622f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
9623f108dbd7SJacob Faibussowitsch 
9624f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
9625f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9626ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
96274f572ea9SToby Isaac   PetscAssertPointer(OrthQual, 4);
96286bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
96299566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
96309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
963163a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
96326ed19f2fSJacob Faibussowitsch   {
96336ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
96346ed19f2fSJacob Faibussowitsch 
96359566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
9636f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
9637f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
9638f108dbd7SJacob Faibussowitsch 
96399566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
964098921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
9641f108dbd7SJacob Faibussowitsch     }
96426ed19f2fSJacob Faibussowitsch   }
9643f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
96444f572ea9SToby Isaac     PetscAssertPointer(OrthQualLabel, 5);
96459566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
96469566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
96479371c9d4SSatish Balay   } else {
96489371c9d4SSatish Balay     *OrthQualLabel = NULL;
96499371c9d4SSatish Balay   }
96509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
96519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
96529566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
96539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
96549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
96559566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
96569566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
96579566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
96589566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
96599566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
96609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
96619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
96629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
96639566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
96649566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
96659566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
96669566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
96679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
96686ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
96696ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9670f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
9671f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
9672898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
9673f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
9674f108dbd7SJacob Faibussowitsch 
96756ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
9676f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
9677f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
96789566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
96799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9680f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
96819566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
96826ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
96836ed19f2fSJacob Faibussowitsch       PetscInt         i;
96846ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
9685f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9686f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
9687f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
9688f108dbd7SJacob Faibussowitsch 
9689f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9690f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
96919566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9692f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
96936ed19f2fSJacob Faibussowitsch       {
96946ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
96956ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
96966ed19f2fSJacob Faibussowitsch 
96979566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
96989566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
96999566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
97006ed19f2fSJacob Faibussowitsch       }
9701f108dbd7SJacob Faibussowitsch 
9702f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9703f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9704f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9705f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9706f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9707addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9708addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9709addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9710f108dbd7SJacob Faibussowitsch       }
9711addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9712addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9713addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9714f108dbd7SJacob Faibussowitsch 
9715f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9716f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9717f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
9718f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
9719f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
9720f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9721f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
9722f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
9723f108dbd7SJacob Faibussowitsch       }
9724ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
9725ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
9726f108dbd7SJacob Faibussowitsch     }
97279566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
97289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9729f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
97306ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9731f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
97329566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9733f108dbd7SJacob Faibussowitsch     }
9734f108dbd7SJacob Faibussowitsch   }
97359566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
97369566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
97379566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
97389566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
97399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
97409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9741f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
97429566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9743f108dbd7SJacob Faibussowitsch   }
97449566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
9745cd791dc2SBarry Smith   PetscCall(PetscOptionsRestoreViewer(&vwr));
97469566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
97473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9748f108dbd7SJacob Faibussowitsch }
9749f108dbd7SJacob Faibussowitsch 
9750d5b43468SJose E. Roman /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
97511eb70e55SToby Isaac  * interpolator construction */
9752d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9753d71ae5a4SJacob Faibussowitsch {
97541eb70e55SToby Isaac   PetscSection section, newSection, gsection;
97551eb70e55SToby Isaac   PetscSF      sf;
97561eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
97571eb70e55SToby Isaac 
97581eb70e55SToby Isaac   PetscFunctionBegin;
97591eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
97604f572ea9SToby Isaac   PetscAssertPointer(odm, 2);
97619566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
97629566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
9763712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
97641eb70e55SToby Isaac   if (!ghasConstraints) {
97659566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
97661eb70e55SToby Isaac     *odm = dm;
97673ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
97681eb70e55SToby Isaac   }
97699566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
97709566063dSJacob Faibussowitsch   PetscCall(DMCopyFields(dm, *odm));
97719566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
97729566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
97739566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
97749566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
97759566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
97763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
97771eb70e55SToby Isaac }
97781eb70e55SToby Isaac 
9779d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9780d71ae5a4SJacob Faibussowitsch {
97811eb70e55SToby Isaac   DM        dmco, dmfo;
97821eb70e55SToby Isaac   Mat       interpo;
97831eb70e55SToby Isaac   Vec       rscale;
97841eb70e55SToby Isaac   Vec       cglobalo, clocal;
97851eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
97861eb70e55SToby Isaac   PetscBool regular;
97871eb70e55SToby Isaac 
97881eb70e55SToby Isaac   PetscFunctionBegin;
97899566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
97909566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
97919566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
97929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
97939566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
97949566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
97959566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
97969566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
97979566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
97989566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
97999566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
98009566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
98019566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
98029566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
98039566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
98049566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
98059566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
98069566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
98079566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
98089566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
98099566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
98109566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
98119566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
98129566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
98131eb70e55SToby Isaac   *shift = fglobal;
98149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
98159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
98169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
98179566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
98189566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
98199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
98209566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
98219566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
98223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98231eb70e55SToby Isaac }
98241eb70e55SToby Isaac 
9825d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9826d71ae5a4SJacob Faibussowitsch {
98271eb70e55SToby Isaac   PetscObject shifto;
98281eb70e55SToby Isaac   Vec         shift;
98291eb70e55SToby Isaac 
98301eb70e55SToby Isaac   PetscFunctionBegin;
98311eb70e55SToby Isaac   if (!interp) {
98321eb70e55SToby Isaac     Vec rscale;
98331eb70e55SToby Isaac 
98349566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
98359566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
98361eb70e55SToby Isaac   } else {
98379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
98381eb70e55SToby Isaac   }
98399566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
98401eb70e55SToby Isaac   if (!shifto) {
98419566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
98429566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
98431eb70e55SToby Isaac     shifto = (PetscObject)shift;
98449566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
98451eb70e55SToby Isaac   }
98461eb70e55SToby Isaac   shift = (Vec)shifto;
98479566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
98489566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
98499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
98503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98511eb70e55SToby Isaac }
98521eb70e55SToby Isaac 
9853bceba477SMatthew G. Knepley /* Pointwise interpolation
9854bceba477SMatthew G. Knepley      Just code FEM for now
9855bceba477SMatthew G. Knepley      u^f = I u^c
98564ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
98574ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
98584ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
9859bceba477SMatthew G. Knepley */
9860d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9861d71ae5a4SJacob Faibussowitsch {
9862bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
9863bceba477SMatthew G. Knepley   PetscInt     m, n;
9864a063dac3SMatthew G. Knepley   void        *ctx;
986568132eb9SMatthew G. Knepley   DM           cdm;
9866cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9867bceba477SMatthew G. Knepley 
9868bceba477SMatthew G. Knepley   PetscFunctionBegin;
98699566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
98709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
98719566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
98729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
987368132eb9SMatthew G. Knepley 
98749566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
98759566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
98769566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
98779566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
98789566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
987968132eb9SMatthew G. Knepley 
98809566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
98819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
98829566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
98839566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
98849566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
98854db47ee9SStefano Zampini   if (scaling) {
98865d1c2e58SMatthew G. Knepley     /* Use naive scaling */
98879566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
98884db47ee9SStefano Zampini   }
98893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9890a063dac3SMatthew G. Knepley }
9891bceba477SMatthew G. Knepley 
9892d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9893d71ae5a4SJacob Faibussowitsch {
98946dbf9973SLawrence Mitchell   VecScatter ctx;
989590748bafSMatthew G. Knepley 
9896a063dac3SMatthew G. Knepley   PetscFunctionBegin;
98979566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
98989566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
98999566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
99003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9901bceba477SMatthew G. Knepley }
9902bceba477SMatthew G. Knepley 
9903d71ae5a4SJacob 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[])
9904d71ae5a4SJacob Faibussowitsch {
990500635df3SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
990600635df3SMatthew G. Knepley   PetscInt       c;
990700635df3SMatthew G. Knepley   for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
99083e9753d6SMatthew G. Knepley }
99093e9753d6SMatthew G. Knepley 
9910d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9911d71ae5a4SJacob Faibussowitsch {
9912b4937a87SMatthew G. Knepley   DM           dmc;
9913b4937a87SMatthew G. Knepley   PetscDS      ds;
9914b4937a87SMatthew G. Knepley   Vec          ones, locmass;
9915b4937a87SMatthew G. Knepley   IS           cellIS;
9916b4937a87SMatthew G. Knepley   PetscFormKey key;
9917b4937a87SMatthew G. Knepley   PetscInt     depth;
9918b4937a87SMatthew G. Knepley 
9919b4937a87SMatthew G. Knepley   PetscFunctionBegin;
99209566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
99219566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
99229566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
99239566063dSJacob Faibussowitsch   PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
99249566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmc, mass));
99259566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &ones));
99269566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &locmass));
99279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmc, &depth));
99289566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
99299566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
99309566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
9931b4937a87SMatthew G. Knepley   key.label = NULL;
9932b4937a87SMatthew G. Knepley   key.value = 0;
9933b4937a87SMatthew G. Knepley   key.field = 0;
9934b4937a87SMatthew G. Knepley   key.part  = 0;
99359566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
99369566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
99379566063dSJacob Faibussowitsch   PetscCall(VecSet(*mass, 0.0));
99389566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
99399566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
99409566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &ones));
99419566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &locmass));
99429566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
99433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9944b4937a87SMatthew G. Knepley }
9945b4937a87SMatthew G. Knepley 
9946d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9947d71ae5a4SJacob Faibussowitsch {
9948bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
9949bd041c0cSMatthew G. Knepley   PetscInt     m, n;
9950bd041c0cSMatthew G. Knepley   void        *ctx;
9951bd041c0cSMatthew G. Knepley   DM           cdm;
9952bd041c0cSMatthew G. Knepley   PetscBool    regular;
9953bd041c0cSMatthew G. Knepley 
9954bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
99553e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
99563e9753d6SMatthew G. Knepley     DM            dmc;
99573e9753d6SMatthew G. Knepley     PetscDS       ds;
9958b4937a87SMatthew G. Knepley     PetscWeakForm wf;
99593e9753d6SMatthew G. Knepley     Vec           u;
99603e9753d6SMatthew G. Knepley     IS            cellIS;
996106ad1575SMatthew G. Knepley     PetscFormKey  key;
99623e9753d6SMatthew G. Knepley     PetscInt      depth;
99633e9753d6SMatthew G. Knepley 
99649566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
99659566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
99669566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
99679566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
99689566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
99699566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
99709566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
99718d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
99729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
99739566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
99749566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
99756528b96dSMatthew G. Knepley     key.label = NULL;
99766528b96dSMatthew G. Knepley     key.value = 0;
99776528b96dSMatthew G. Knepley     key.field = 0;
997806ad1575SMatthew G. Knepley     key.part  = 0;
99799566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
99809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
99818d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
99829566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
99833e9753d6SMatthew G. Knepley   } else {
99849566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
99859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
99869566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
99879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
9988bd041c0cSMatthew G. Knepley 
99899566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
99909566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
99919566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
99929566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
9993bd041c0cSMatthew G. Knepley 
99949566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
99959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
99969566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
99979566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
99983e9753d6SMatthew G. Knepley   }
99999566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
100003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10001bd041c0cSMatthew G. Knepley }
10002bd041c0cSMatthew G. Knepley 
100030aef6b92SMatthew G. Knepley /*@
100040aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
100050aef6b92SMatthew G. Knepley 
100060aef6b92SMatthew G. Knepley   Input Parameter:
10007a1cb98faSBarry Smith . dm - The `DMPLEX` object
100080aef6b92SMatthew G. Knepley 
100090aef6b92SMatthew G. Knepley   Output Parameter:
100100aef6b92SMatthew G. Knepley . regular - The flag
100110aef6b92SMatthew G. Knepley 
100120aef6b92SMatthew G. Knepley   Level: intermediate
100130aef6b92SMatthew G. Knepley 
100141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
100150aef6b92SMatthew G. Knepley @*/
10016d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
10017d71ae5a4SJacob Faibussowitsch {
100180aef6b92SMatthew G. Knepley   PetscFunctionBegin;
100190aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100204f572ea9SToby Isaac   PetscAssertPointer(regular, 2);
100210aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
100223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100230aef6b92SMatthew G. Knepley }
100240aef6b92SMatthew G. Knepley 
100250aef6b92SMatthew G. Knepley /*@
100260aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
100270aef6b92SMatthew G. Knepley 
100280aef6b92SMatthew G. Knepley   Input Parameters:
10029a1cb98faSBarry Smith + dm      - The `DMPLEX` object
100300aef6b92SMatthew G. Knepley - regular - The flag
100310aef6b92SMatthew G. Knepley 
100320aef6b92SMatthew G. Knepley   Level: intermediate
100330aef6b92SMatthew G. Knepley 
100341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
100350aef6b92SMatthew G. Knepley @*/
10036d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
10037d71ae5a4SJacob Faibussowitsch {
100380aef6b92SMatthew G. Knepley   PetscFunctionBegin;
100390aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100400aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
100413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100420aef6b92SMatthew G. Knepley }
100430aef6b92SMatthew G. Knepley 
10044a68b90caSToby Isaac /*@
10045f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
10046a1cb98faSBarry Smith   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
10047a68b90caSToby Isaac 
10048a1cb98faSBarry Smith   Not Collective
10049a68b90caSToby Isaac 
10050f899ff85SJose E. Roman   Input Parameter:
10051a1cb98faSBarry Smith . dm - The `DMPLEX` object
10052a68b90caSToby Isaac 
10053a68b90caSToby Isaac   Output Parameters:
1005420f4b53cSBarry Smith + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
1005520f4b53cSBarry Smith - anchorIS      - If not `NULL`, set to the list of anchors indexed by `anchorSection`
10056a68b90caSToby Isaac 
10057a68b90caSToby Isaac   Level: intermediate
10058a68b90caSToby Isaac 
100591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
10060a68b90caSToby Isaac @*/
10061d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
10062d71ae5a4SJacob Faibussowitsch {
10063a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
10064a68b90caSToby Isaac 
10065a68b90caSToby Isaac   PetscFunctionBegin;
10066a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100679566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
10068a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
10069a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
100703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10071a68b90caSToby Isaac }
10072a68b90caSToby Isaac 
10073a68b90caSToby Isaac /*@
10074a4e35b19SJacob Faibussowitsch   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.
10075a68b90caSToby Isaac 
1007620f4b53cSBarry Smith   Collective
10077a68b90caSToby Isaac 
10078a68b90caSToby Isaac   Input Parameters:
10079a1cb98faSBarry Smith + dm            - The `DMPLEX` object
10080a1cb98faSBarry Smith . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
10081a1cb98faSBarry Smith                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10082a1cb98faSBarry Smith - anchorIS      - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10083a68b90caSToby Isaac 
10084a68b90caSToby Isaac   Level: intermediate
10085a68b90caSToby Isaac 
10086a1cb98faSBarry Smith   Notes:
10087a4e35b19SJacob Faibussowitsch   Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to
10088a4e35b19SJacob Faibussowitsch   an outside value, the anchor constraints set a point's degrees of freedom to be a linear
10089a4e35b19SJacob Faibussowitsch   combination of other points' degrees of freedom.
10090a4e35b19SJacob Faibussowitsch 
10091a1cb98faSBarry Smith   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
10092a1cb98faSBarry Smith   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
10093a1cb98faSBarry Smith 
1009420f4b53cSBarry Smith   The reference counts of `anchorSection` and `anchorIS` are incremented.
10095a1cb98faSBarry Smith 
100961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
10097a68b90caSToby Isaac @*/
10098d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
10099d71ae5a4SJacob Faibussowitsch {
10100a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
10101e228b242SToby Isaac   PetscMPIInt result;
10102a68b90caSToby Isaac 
10103a68b90caSToby Isaac   PetscFunctionBegin;
10104a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10105e228b242SToby Isaac   if (anchorSection) {
10106e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
101079566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
101081dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
10109e228b242SToby Isaac   }
10110e228b242SToby Isaac   if (anchorIS) {
10111e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
101129566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
101131dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
10114e228b242SToby Isaac   }
10115a68b90caSToby Isaac 
101169566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
101179566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
10118a68b90caSToby Isaac   plex->anchorSection = anchorSection;
10119a68b90caSToby Isaac 
101209566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
101219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
10122a68b90caSToby Isaac   plex->anchorIS = anchorIS;
10123a68b90caSToby Isaac 
10124cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
10125a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
10126a68b90caSToby Isaac     const PetscInt *anchors;
10127a68b90caSToby Isaac 
101289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
101299566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
101309566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
10131a68b90caSToby Isaac     for (a = 0; a < size; a++) {
10132a68b90caSToby Isaac       PetscInt p;
10133a68b90caSToby Isaac 
10134a68b90caSToby Isaac       p = anchors[a];
10135a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
10136a68b90caSToby Isaac         PetscInt dof;
10137a68b90caSToby Isaac 
101389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10139a68b90caSToby Isaac         if (dof) {
101409566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
1014163a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
10142a68b90caSToby Isaac         }
10143a68b90caSToby Isaac       }
10144a68b90caSToby Isaac     }
101459566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
10146a68b90caSToby Isaac   }
10147f7c74593SToby Isaac   /* reset the generic constraints */
101489566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
101493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10150a68b90caSToby Isaac }
10151a68b90caSToby Isaac 
10152d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
10153d71ae5a4SJacob Faibussowitsch {
10154f7c74593SToby Isaac   PetscSection anchorSection;
101556995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
10156a68b90caSToby Isaac 
10157a68b90caSToby Isaac   PetscFunctionBegin;
10158a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
101599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
101609566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
101619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
101626995de1eSToby Isaac   if (numFields) {
10163719ab38cSToby Isaac     PetscInt f;
101649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
10165719ab38cSToby Isaac 
10166719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
10167719ab38cSToby Isaac       PetscInt numComp;
10168719ab38cSToby Isaac 
101699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
101709566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
10171719ab38cSToby Isaac     }
101726995de1eSToby Isaac   }
101739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
101749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
101756995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
101766995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
101776995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
101789566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
10179a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
101809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10181a68b90caSToby Isaac     if (dof) {
101829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
101839566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
10184a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
101859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
101869566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
10187a68b90caSToby Isaac       }
10188a68b90caSToby Isaac     }
10189a68b90caSToby Isaac   }
101909566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
101919566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
101923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10193a68b90caSToby Isaac }
10194a68b90caSToby Isaac 
10195d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
10196d71ae5a4SJacob Faibussowitsch {
10197f7c74593SToby Isaac   PetscSection    aSec;
10198ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
101990ac89760SToby Isaac   const PetscInt *anchors;
102000ac89760SToby Isaac   PetscInt        numFields, f;
1020166ad2231SToby Isaac   IS              aIS;
10202e19f7ee6SMark Adams   MatType         mtype;
10203e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
102040ac89760SToby Isaac 
102050ac89760SToby Isaac   PetscFunctionBegin;
102060ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
102089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
102099566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
102109566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
102119566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
102129566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
102139566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
102149566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
10215e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
10216e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
10217e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
102189566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
102199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
102209566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
102216995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
102229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
102239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
102249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
102250ac89760SToby Isaac   i[0] = 0;
102269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
102270ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
10228f19733c5SToby Isaac     PetscInt rDof, rOff, r;
10229f19733c5SToby Isaac 
102309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10231f19733c5SToby Isaac     if (!rDof) continue;
102329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
102330ac89760SToby Isaac     if (numFields) {
102340ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
102350ac89760SToby Isaac         annz = 0;
10236f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
10237f19733c5SToby Isaac           a = anchors[rOff + r];
10238ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
102399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
102400ac89760SToby Isaac           annz += aDof;
102410ac89760SToby Isaac         }
102429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
102439566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10244ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
102450ac89760SToby Isaac       }
102462f7452b8SBarry Smith     } else {
102470ac89760SToby Isaac       annz = 0;
102489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
102490ac89760SToby Isaac       for (q = 0; q < dof; q++) {
10250ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
10251ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
102529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
102530ac89760SToby Isaac         annz += aDof;
102540ac89760SToby Isaac       }
102559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
102569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10257ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
102580ac89760SToby Isaac     }
102590ac89760SToby Isaac   }
102600ac89760SToby Isaac   nnz = i[m];
102619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
102620ac89760SToby Isaac   offset = 0;
102630ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
102640ac89760SToby Isaac     if (numFields) {
102650ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
102669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
102670ac89760SToby Isaac         for (q = 0; q < dof; q++) {
102680ac89760SToby Isaac           PetscInt rDof, rOff, r;
102699566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
102709566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
102710ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
102720ac89760SToby Isaac             PetscInt s;
102730ac89760SToby Isaac 
102740ac89760SToby Isaac             a = anchors[rOff + r];
10275ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
102769566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
102779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10278ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
102790ac89760SToby Isaac           }
102800ac89760SToby Isaac         }
102810ac89760SToby Isaac       }
102822f7452b8SBarry Smith     } else {
102839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
102840ac89760SToby Isaac       for (q = 0; q < dof; q++) {
102850ac89760SToby Isaac         PetscInt rDof, rOff, r;
102869566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
102879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
102880ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
102890ac89760SToby Isaac           PetscInt s;
102900ac89760SToby Isaac 
102910ac89760SToby Isaac           a = anchors[rOff + r];
10292ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
102939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
102949566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10295ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
102960ac89760SToby Isaac         }
102970ac89760SToby Isaac       }
102980ac89760SToby Isaac     }
102990ac89760SToby Isaac   }
103009566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
103019566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
103029566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
103039566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
103043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103050ac89760SToby Isaac }
103060ac89760SToby Isaac 
10307d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10308d71ae5a4SJacob Faibussowitsch {
10309f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
10310f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
1031166ad2231SToby Isaac   Mat          cMat;
1031266ad2231SToby Isaac 
1031366ad2231SToby Isaac   PetscFunctionBegin;
1031466ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
103159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
1031666ad2231SToby Isaac   if (anchorSection) {
1031744a7f3ddSMatthew G. Knepley     PetscInt Nf;
10318e228b242SToby Isaac 
103199566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
103209566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
103219566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
103229566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
103239566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
103249566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
103259566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
103269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
1032766ad2231SToby Isaac   }
103283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1032966ad2231SToby Isaac }
10330a93c429eSMatthew G. Knepley 
10331d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10332d71ae5a4SJacob Faibussowitsch {
10333a93c429eSMatthew G. Knepley   IS           subis;
10334a93c429eSMatthew G. Knepley   PetscSection section, subsection;
10335a93c429eSMatthew G. Knepley 
10336a93c429eSMatthew G. Knepley   PetscFunctionBegin;
103379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1033828b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
1033928b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10340a93c429eSMatthew G. Knepley   /* Create subdomain */
103419566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dm, label, value, subdm));
10342a93c429eSMatthew G. Knepley   /* Create submodel */
103439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
103449566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
103459566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
103469566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
103479566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
10348a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
10349a93c429eSMatthew G. Knepley   if (is) {
10350a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
10351a93c429eSMatthew G. Knepley     IS              spIS;
10352a93c429eSMatthew G. Knepley     const PetscInt *spmap;
10353a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
10354a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10355a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10356a93c429eSMatthew G. Knepley 
103579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
103589566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
103599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
103609566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
103619566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
103629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10363a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10364a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10365a93c429eSMatthew G. Knepley 
103669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10367a93c429eSMatthew G. Knepley       if (gdof > 0) {
10368a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10369a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10370a93c429eSMatthew G. Knepley 
103719566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
103729566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10373a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10374a93c429eSMatthew G. Knepley         }
10375a93c429eSMatthew G. Knepley         subSize += pSubSize;
10376a93c429eSMatthew G. Knepley         if (pSubSize) {
10377a93c429eSMatthew G. Knepley           if (bs < 0) {
10378a93c429eSMatthew G. Knepley             bs = pSubSize;
10379a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10380a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10381a93c429eSMatthew G. Knepley             bs = 1;
10382a93c429eSMatthew G. Knepley           }
10383a93c429eSMatthew G. Knepley         }
10384a93c429eSMatthew G. Knepley       }
10385a93c429eSMatthew G. Knepley     }
10386a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
103879371c9d4SSatish Balay     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
103889371c9d4SSatish Balay     bsLocal[1] = bs;
103899566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
103909371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
103919371c9d4SSatish Balay       bs = 1;
103929371c9d4SSatish Balay     } else {
103939371c9d4SSatish Balay       bs = bsMinMax[0];
103949371c9d4SSatish Balay     }
103959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10396a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10397a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10398a93c429eSMatthew G. Knepley 
103999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10400a93c429eSMatthew G. Knepley       if (gdof > 0) {
10401a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10402a93c429eSMatthew G. Knepley 
104039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10404a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10405a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10406a93c429eSMatthew G. Knepley 
10407a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10408a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
104099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
104109566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10411a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10412a93c429eSMatthew G. Knepley           }
104139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
104149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10415ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10416a93c429eSMatthew G. Knepley         }
10417a93c429eSMatthew G. Knepley       }
10418a93c429eSMatthew G. Knepley     }
104199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
104209566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10421a93c429eSMatthew G. Knepley     if (bs > 1) {
10422a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10423a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10424a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10425a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
104269371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
104279371c9d4SSatish Balay             set = 0;
104289371c9d4SSatish Balay             break;
104299371c9d4SSatish Balay           }
10430a93c429eSMatthew G. Knepley         }
10431a93c429eSMatthew G. Knepley       }
104329566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10433a93c429eSMatthew G. Knepley     }
10434a93c429eSMatthew G. Knepley     /* Attach nullspace */
10435a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
10436a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10437a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
10438a93c429eSMatthew G. Knepley     }
10439a93c429eSMatthew G. Knepley     if (f < Nf) {
10440a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
104419566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
104426823f3c5SBlaise Bourdin 
104439566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
104449566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
10445a93c429eSMatthew G. Knepley     }
10446a93c429eSMatthew G. Knepley   }
104473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10448a93c429eSMatthew G. Knepley }
10449c0f0dcc3SMatthew G. Knepley 
10450c0f0dcc3SMatthew G. Knepley /*@
10451c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10452c0f0dcc3SMatthew G. Knepley 
10453a1cb98faSBarry Smith   Input Parameters:
10454a1cb98faSBarry Smith + dm    - The `DM`
10455a1cb98faSBarry Smith - dummy - unused argument
10456a1cb98faSBarry Smith 
10457a1cb98faSBarry Smith   Options Database Key:
10458a1cb98faSBarry Smith . -dm_plex_monitor_throughput - Activate the monitor
10459c0f0dcc3SMatthew G. Knepley 
10460c0f0dcc3SMatthew G. Knepley   Level: developer
10461c0f0dcc3SMatthew G. Knepley 
104621cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10463c0f0dcc3SMatthew G. Knepley @*/
10464d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
10465d71ae5a4SJacob Faibussowitsch {
10466b665b14eSToby Isaac   PetscLogHandler default_handler;
10467b665b14eSToby Isaac 
104682611ad71SToby Isaac   PetscFunctionBegin;
104692611ad71SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10470b665b14eSToby Isaac   PetscCall(PetscLogGetDefaultHandler(&default_handler));
10471b665b14eSToby Isaac   if (default_handler) {
10472c0f0dcc3SMatthew G. Knepley     PetscLogEvent      event;
10473c0f0dcc3SMatthew G. Knepley     PetscEventPerfInfo eventInfo;
10474c0f0dcc3SMatthew G. Knepley     PetscReal          cellRate, flopRate;
10475c0f0dcc3SMatthew G. Knepley     PetscInt           cStart, cEnd, Nf, N;
10476c0f0dcc3SMatthew G. Knepley     const char        *name;
10477c0f0dcc3SMatthew G. Knepley 
104789566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
104799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
104809566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
104819566063dSJacob Faibussowitsch     PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
10482b665b14eSToby Isaac     PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo));
10483c0f0dcc3SMatthew G. Knepley     N        = (cEnd - cStart) * Nf * eventInfo.count;
10484c0f0dcc3SMatthew G. Knepley     flopRate = eventInfo.flops / eventInfo.time;
10485c0f0dcc3SMatthew G. Knepley     cellRate = N / eventInfo.time;
1048663a3b9bcSJacob 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)));
104872611ad71SToby Isaac   } else {
10488b665b14eSToby 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.");
104892611ad71SToby Isaac   }
104903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10491c0f0dcc3SMatthew G. Knepley }
10492