xref: /petsc/src/dm/impls/plex/plex.c (revision c5aedaa35e5e61de3211eed738d07e90ce94def1)
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);
1087bd3611e6SMatthew 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;
1251bd3611e6SMatthew 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 
1764*c5aedaa3SMatthew G. Knepley static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1765d71ae5a4SJacob Faibussowitsch {
1766e5c487bfSMatthew G. Knepley   PetscReal   centroid[2] = {0., 0.};
1767e5c487bfSMatthew G. Knepley   PetscMPIInt rank;
1768*c5aedaa3SMatthew G. Knepley   PetscInt    fillColor;
1769e5c487bfSMatthew G. Knepley 
1770e5c487bfSMatthew G. Knepley   PetscFunctionBegin;
17719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1772e5c487bfSMatthew G. Knepley   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1773*c5aedaa3SMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
1774*c5aedaa3SMatthew G. Knepley     centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv;
1775*c5aedaa3SMatthew G. Knepley     centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv;
17769371c9d4SSatish Balay   }
1777*c5aedaa3SMatthew G. Knepley   for (PetscInt e = 0; e < Nv; ++e) {
1778e5c487bfSMatthew G. Knepley     refCoords[0] = refVertices[e * 2 + 0];
1779e5c487bfSMatthew G. Knepley     refCoords[1] = refVertices[e * 2 + 1];
1780*c5aedaa3SMatthew G. Knepley     for (PetscInt d = 1; d <= edgeDiv; ++d) {
1781*c5aedaa3SMatthew G. Knepley       refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv;
1782*c5aedaa3SMatthew G. Knepley       refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv;
1783e5c487bfSMatthew G. Knepley     }
17849566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1785*c5aedaa3SMatthew G. Knepley     for (PetscInt d = 0; d < edgeDiv; ++d) {
17869566063dSJacob 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));
17879566063dSJacob 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));
1788e5c487bfSMatthew G. Knepley     }
1789e5c487bfSMatthew G. Knepley   }
1790*c5aedaa3SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1791*c5aedaa3SMatthew G. Knepley }
1792*c5aedaa3SMatthew G. Knepley 
1793*c5aedaa3SMatthew G. Knepley static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1794*c5aedaa3SMatthew G. Knepley {
1795*c5aedaa3SMatthew G. Knepley   DMPolytopeType ct;
1796*c5aedaa3SMatthew G. Knepley 
1797*c5aedaa3SMatthew G. Knepley   PetscFunctionBegin;
1798*c5aedaa3SMatthew G. Knepley   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1799*c5aedaa3SMatthew G. Knepley   switch (ct) {
1800*c5aedaa3SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE: {
1801*c5aedaa3SMatthew G. Knepley     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1802*c5aedaa3SMatthew G. Knepley 
1803*c5aedaa3SMatthew G. Knepley     PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords));
1804*c5aedaa3SMatthew G. Knepley   } break;
1805*c5aedaa3SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL: {
1806*c5aedaa3SMatthew G. Knepley     PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.};
1807*c5aedaa3SMatthew G. Knepley 
1808*c5aedaa3SMatthew G. Knepley     PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords));
18099371c9d4SSatish Balay   } break;
1810d71ae5a4SJacob Faibussowitsch   default:
1811d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1812e5c487bfSMatthew G. Knepley   }
18133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1814e5c487bfSMatthew G. Knepley }
1815e5c487bfSMatthew G. Knepley 
1816d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1817d71ae5a4SJacob Faibussowitsch {
1818e412dcbdSMatthew G. Knepley   PetscDraw    draw;
1819e412dcbdSMatthew G. Knepley   DM           cdm;
1820e412dcbdSMatthew G. Knepley   PetscSection coordSection;
1821e412dcbdSMatthew G. Knepley   Vec          coordinates;
1822c9c77995SMatthew G. Knepley   PetscReal    xyl[3], xyr[3];
1823e5c487bfSMatthew G. Knepley   PetscReal   *refCoords, *edgeCoords;
1824*c5aedaa3SMatthew G. Knepley   PetscBool    isnull, drawAffine;
1825*c5aedaa3SMatthew G. Knepley   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv;
1826e412dcbdSMatthew G. Knepley 
1827e412dcbdSMatthew G. Knepley   PetscFunctionBegin;
18289566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
182963a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1830*c5aedaa3SMatthew G. Knepley   PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree));
1831*c5aedaa3SMatthew G. Knepley   drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE;
1832*c5aedaa3SMatthew G. Knepley   edgeDiv    = cDegree + 1;
18339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
18349566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
18359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
18369566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(cdm, &coordSection));
18379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
18389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
18399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1840e412dcbdSMatthew G. Knepley 
18419566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
18429566063dSJacob Faibussowitsch   PetscCall(PetscDrawIsNull(draw, &isnull));
18433ba16761SJacob Faibussowitsch   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
18449566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1845e412dcbdSMatthew G. Knepley 
1846c9c77995SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
18479566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
18489566063dSJacob Faibussowitsch   PetscCall(PetscDrawClear(draw));
1849e412dcbdSMatthew G. Knepley 
1850cf3064d3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1851cf3064d3SMatthew G. Knepley     PetscScalar       *coords = NULL;
1852c9c77995SMatthew G. Knepley     const PetscScalar *coords_arr;
1853ba2698f1SMatthew G. Knepley     PetscInt           numCoords;
1854c9c77995SMatthew G. Knepley     PetscBool          isDG;
1855cf3064d3SMatthew G. Knepley 
1856c9c77995SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
18571baa6e33SBarry Smith     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
18581baa6e33SBarry Smith     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1859c9c77995SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1860cf3064d3SMatthew G. Knepley   }
18619566063dSJacob Faibussowitsch   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
18629566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
18639566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
18649566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
18653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1866e412dcbdSMatthew G. Knepley }
1867e412dcbdSMatthew G. Knepley 
1868e44f6aebSMatthew G. Knepley static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm)
1869e44f6aebSMatthew G. Knepley {
1870e44f6aebSMatthew G. Knepley   DM           odm = dm, rdm = dm, cdm;
1871e44f6aebSMatthew G. Knepley   PetscFE      fe;
1872e44f6aebSMatthew G. Knepley   PetscSpace   sp;
1873e44f6aebSMatthew G. Knepley   PetscClassId id;
1874e44f6aebSMatthew G. Knepley   PetscInt     degree;
1875e44f6aebSMatthew G. Knepley   PetscBool    hoView = PETSC_TRUE;
1876e44f6aebSMatthew G. Knepley 
1877e44f6aebSMatthew G. Knepley   PetscFunctionBegin;
1878e44f6aebSMatthew G. Knepley   PetscObjectOptionsBegin((PetscObject)dm);
1879e44f6aebSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL));
1880e44f6aebSMatthew G. Knepley   PetscOptionsEnd();
1881e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)dm));
1882e44f6aebSMatthew G. Knepley   *hdm = dm;
1883e44f6aebSMatthew G. Knepley   if (!hoView) PetscFunctionReturn(PETSC_SUCCESS);
1884e44f6aebSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
1885e44f6aebSMatthew G. Knepley   PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
1886e44f6aebSMatthew G. Knepley   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
1887e44f6aebSMatthew G. Knepley   if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS);
1888e44f6aebSMatthew G. Knepley   PetscCall(PetscFEGetBasisSpace(fe, &sp));
1889e44f6aebSMatthew G. Knepley   PetscCall(PetscSpaceGetDegree(sp, &degree, NULL));
1890e44f6aebSMatthew G. Knepley   for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) {
1891e44f6aebSMatthew G. Knepley     DM  cdm, rcdm;
1892e44f6aebSMatthew G. Knepley     Mat In;
1893e44f6aebSMatthew G. Knepley     Vec cl, rcl;
1894e44f6aebSMatthew G. Knepley 
1895e44f6aebSMatthew G. Knepley     PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm));
1896*c5aedaa3SMatthew G. Knepley     PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL));
1897e44f6aebSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates"));
1898e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(odm, &cdm));
1899e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(rdm, &rcdm));
1900e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(odm, &cl));
1901e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(rdm, &rcl));
1902e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoarseDM(rcdm, cdm));
1903e44f6aebSMatthew G. Knepley     PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL));
1904e44f6aebSMatthew G. Knepley     PetscCall(MatMult(In, cl, rcl));
1905e44f6aebSMatthew G. Knepley     PetscCall(MatDestroy(&In));
1906e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinatesLocal(rdm, rcl));
1907e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&odm));
1908e44f6aebSMatthew G. Knepley     odm = rdm;
1909e44f6aebSMatthew G. Knepley   }
1910e44f6aebSMatthew G. Knepley   *hdm = rdm;
1911e44f6aebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1912e44f6aebSMatthew G. Knepley }
1913e44f6aebSMatthew G. Knepley 
19141e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
19151e50132fSMatthew G. Knepley   #include <exodusII.h>
19166823f3c5SBlaise Bourdin   #include <petscviewerexodusii.h>
19171e50132fSMatthew G. Knepley #endif
19181e50132fSMatthew G. Knepley 
1919d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1920d71ae5a4SJacob Faibussowitsch {
19215f34f2dcSJed Brown   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1922002a2709SMatthew G. Knepley   char      name[PETSC_MAX_PATH_LEN];
1923552f7358SJed Brown 
1924552f7358SJed Brown   PetscFunctionBegin;
1925552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1926552f7358SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19279566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
19289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
19299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
19319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
19329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
19335f34f2dcSJed Brown   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1934552f7358SJed Brown   if (iascii) {
19358135c375SStefano Zampini     PetscViewerFormat format;
19369566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
19371baa6e33SBarry Smith     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
19381baa6e33SBarry Smith     else PetscCall(DMPlexView_Ascii(dm, viewer));
1939c6ccd67eSMatthew G. Knepley   } else if (ishdf5) {
1940c6ccd67eSMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
19419566063dSJacob Faibussowitsch     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1942c6ccd67eSMatthew G. Knepley #else
1943c6ccd67eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1944552f7358SJed Brown #endif
1945e412dcbdSMatthew G. Knepley   } else if (isvtk) {
19469566063dSJacob Faibussowitsch     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1947e412dcbdSMatthew G. Knepley   } else if (isdraw) {
1948e44f6aebSMatthew G. Knepley     DM hdm;
1949e44f6aebSMatthew G. Knepley 
1950e44f6aebSMatthew G. Knepley     PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm));
1951e44f6aebSMatthew G. Knepley     PetscCall(DMPlexView_Draw(hdm, viewer));
1952e44f6aebSMatthew G. Knepley     PetscCall(DMDestroy(&hdm));
19538135c375SStefano Zampini   } else if (isglvis) {
19549566063dSJacob Faibussowitsch     PetscCall(DMPlexView_GLVis(dm, viewer));
19551e50132fSMatthew G. Knepley #if defined(PETSC_HAVE_EXODUSII)
19561e50132fSMatthew G. Knepley   } else if (isexodus) {
19576823f3c5SBlaise Bourdin     /*
19586823f3c5SBlaise Bourdin       exodusII requires that all sets be part of exactly one cell set.
19596823f3c5SBlaise Bourdin       If the dm does not have a "Cell Sets" label defined, we create one
1960da81f932SPierre Jolivet       with ID 1, containing all cells.
19616823f3c5SBlaise Bourdin       Note that if the Cell Sets label is defined but does not cover all cells,
19626823f3c5SBlaise Bourdin       we may still have a problem. This should probably be checked here or in the viewer;
19636823f3c5SBlaise Bourdin     */
19646823f3c5SBlaise Bourdin     PetscInt numCS;
19659566063dSJacob Faibussowitsch     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
19666823f3c5SBlaise Bourdin     if (!numCS) {
19671e50132fSMatthew G. Knepley       PetscInt cStart, cEnd, c;
19689566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dm, "Cell Sets"));
19699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
19709566063dSJacob Faibussowitsch       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
19716823f3c5SBlaise Bourdin     }
19729566063dSJacob Faibussowitsch     PetscCall(DMView_PlexExodusII(dm, viewer));
19731e50132fSMatthew G. Knepley #endif
19745f34f2dcSJed Brown #if defined(PETSC_HAVE_CGNS)
19755f34f2dcSJed Brown   } else if (iscgns) {
19765f34f2dcSJed Brown     PetscCall(DMView_PlexCGNS(dm, viewer));
19775f34f2dcSJed Brown #endif
19781baa6e33SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1979cb3ba0daSMatthew G. Knepley   /* Optionally view the partition */
19809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1981cb3ba0daSMatthew G. Knepley   if (flg) {
1982cb3ba0daSMatthew G. Knepley     Vec ranks;
19839566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRankField(dm, &ranks));
19849566063dSJacob Faibussowitsch     PetscCall(VecView(ranks, viewer));
19859566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ranks));
1986cb3ba0daSMatthew G. Knepley   }
1987002a2709SMatthew G. Knepley   /* Optionally view a label */
19889566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1989002a2709SMatthew G. Knepley   if (flg) {
1990002a2709SMatthew G. Knepley     DMLabel label;
1991002a2709SMatthew G. Knepley     Vec     val;
1992002a2709SMatthew G. Knepley 
19939566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, name, &label));
199428b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
19959566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateLabelField(dm, label, &val));
19969566063dSJacob Faibussowitsch     PetscCall(VecView(val, viewer));
19979566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&val));
1998002a2709SMatthew G. Knepley   }
19993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2000552f7358SJed Brown }
2001552f7358SJed Brown 
20027f96f51bSksagiyam /*@
2003a1cb98faSBarry Smith   DMPlexTopologyView - Saves a `DMPLEX` topology into a file
20047f96f51bSksagiyam 
200520f4b53cSBarry Smith   Collective
20067f96f51bSksagiyam 
20077f96f51bSksagiyam   Input Parameters:
2008a1cb98faSBarry Smith + dm     - The `DM` whose topology is to be saved
2009a1cb98faSBarry Smith - viewer - The `PetscViewer` to save it in
20107f96f51bSksagiyam 
20117f96f51bSksagiyam   Level: advanced
20127f96f51bSksagiyam 
20131cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
20147f96f51bSksagiyam @*/
2015d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
2016d71ae5a4SJacob Faibussowitsch {
20177f96f51bSksagiyam   PetscBool ishdf5;
20187f96f51bSksagiyam 
20197f96f51bSksagiyam   PetscFunctionBegin;
20207f96f51bSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20217f96f51bSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20229566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
20247f96f51bSksagiyam   if (ishdf5) {
20257f96f51bSksagiyam #if defined(PETSC_HAVE_HDF5)
20267f96f51bSksagiyam     PetscViewerFormat format;
20279566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
20287f96f51bSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20297f96f51bSksagiyam       IS globalPointNumbering;
20307f96f51bSksagiyam 
20319566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
20329566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
20339566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
203498921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
20357f96f51bSksagiyam #else
20367f96f51bSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
20377f96f51bSksagiyam #endif
20387f96f51bSksagiyam   }
20399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
20403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20417f96f51bSksagiyam }
20427f96f51bSksagiyam 
204377b8e257Sksagiyam /*@
2044a1cb98faSBarry Smith   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
204577b8e257Sksagiyam 
204620f4b53cSBarry Smith   Collective
204777b8e257Sksagiyam 
204877b8e257Sksagiyam   Input Parameters:
2049a1cb98faSBarry Smith + dm     - The `DM` whose coordinates are to be saved
2050a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
205177b8e257Sksagiyam 
205277b8e257Sksagiyam   Level: advanced
205377b8e257Sksagiyam 
20541cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
205577b8e257Sksagiyam @*/
2056d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
2057d71ae5a4SJacob Faibussowitsch {
205877b8e257Sksagiyam   PetscBool ishdf5;
205977b8e257Sksagiyam 
206077b8e257Sksagiyam   PetscFunctionBegin;
206177b8e257Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
206277b8e257Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
20639566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
20649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
206577b8e257Sksagiyam   if (ishdf5) {
206677b8e257Sksagiyam #if defined(PETSC_HAVE_HDF5)
206777b8e257Sksagiyam     PetscViewerFormat format;
20689566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
206977b8e257Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
20709566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
2071fe28d297SMatthew Knepley     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
207277b8e257Sksagiyam #else
207377b8e257Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
207477b8e257Sksagiyam #endif
207577b8e257Sksagiyam   }
20769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
20773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
207877b8e257Sksagiyam }
207977b8e257Sksagiyam 
2080bd6565f1Sksagiyam /*@
2081a1cb98faSBarry Smith   DMPlexLabelsView - Saves `DMPLEX` labels into a file
2082bd6565f1Sksagiyam 
208320f4b53cSBarry Smith   Collective
2084bd6565f1Sksagiyam 
2085bd6565f1Sksagiyam   Input Parameters:
2086a1cb98faSBarry Smith + dm     - The `DM` whose labels are to be saved
2087a1cb98faSBarry Smith - viewer - The `PetscViewer` for saving
2088bd6565f1Sksagiyam 
2089bd6565f1Sksagiyam   Level: advanced
2090bd6565f1Sksagiyam 
20911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
2092bd6565f1Sksagiyam @*/
2093d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
2094d71ae5a4SJacob Faibussowitsch {
2095bd6565f1Sksagiyam   PetscBool ishdf5;
2096bd6565f1Sksagiyam 
2097bd6565f1Sksagiyam   PetscFunctionBegin;
2098bd6565f1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2099bd6565f1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
21009566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
2102bd6565f1Sksagiyam   if (ishdf5) {
2103bd6565f1Sksagiyam #if defined(PETSC_HAVE_HDF5)
2104bd6565f1Sksagiyam     IS                globalPointNumbering;
2105bd6565f1Sksagiyam     PetscViewerFormat format;
2106bd6565f1Sksagiyam 
21079566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2108bd6565f1Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
21099566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
21109566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
21119566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalPointNumbering));
211298921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2113bd6565f1Sksagiyam #else
2114bd6565f1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2115bd6565f1Sksagiyam #endif
2116bd6565f1Sksagiyam   }
21179566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
21183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2119bd6565f1Sksagiyam }
2120bd6565f1Sksagiyam 
2121021affd3Sksagiyam /*@
2122a1cb98faSBarry Smith   DMPlexSectionView - Saves a section associated with a `DMPLEX`
2123021affd3Sksagiyam 
212420f4b53cSBarry Smith   Collective
2125021affd3Sksagiyam 
2126021affd3Sksagiyam   Input Parameters:
2127a1cb98faSBarry Smith + dm        - The `DM` that contains the topology on which the section to be saved is defined
2128a1cb98faSBarry Smith . viewer    - The `PetscViewer` for saving
2129a1cb98faSBarry Smith - sectiondm - The `DM` that contains the section to be saved
2130021affd3Sksagiyam 
2131021affd3Sksagiyam   Level: advanced
2132021affd3Sksagiyam 
2133021affd3Sksagiyam   Notes:
2134420bcc1bSBarry 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.
2135021affd3Sksagiyam 
2136420bcc1bSBarry 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.
2137021affd3Sksagiyam 
21381cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
2139021affd3Sksagiyam @*/
2140d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
2141d71ae5a4SJacob Faibussowitsch {
2142021affd3Sksagiyam   PetscBool ishdf5;
2143021affd3Sksagiyam 
2144021affd3Sksagiyam   PetscFunctionBegin;
2145021affd3Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2146021affd3Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2147021affd3Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
21489566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
21499566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
2150021affd3Sksagiyam   if (ishdf5) {
2151021affd3Sksagiyam #if defined(PETSC_HAVE_HDF5)
21529566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
2153021affd3Sksagiyam #else
2154021affd3Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2155021affd3Sksagiyam #endif
2156021affd3Sksagiyam   }
21579566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
21583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2159021affd3Sksagiyam }
2160021affd3Sksagiyam 
21613e97647fSksagiyam /*@
21623e97647fSksagiyam   DMPlexGlobalVectorView - Saves a global vector
21633e97647fSksagiyam 
216420f4b53cSBarry Smith   Collective
21653e97647fSksagiyam 
21663e97647fSksagiyam   Input Parameters:
2167a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2168a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
2169a1cb98faSBarry Smith . sectiondm - The `DM` that contains the global section on which vec is defined
21703e97647fSksagiyam - vec       - The global vector to be saved
21713e97647fSksagiyam 
21723e97647fSksagiyam   Level: advanced
21733e97647fSksagiyam 
21743e97647fSksagiyam   Notes:
2175420bcc1bSBarry 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.
21763e97647fSksagiyam 
217760225df5SJacob Faibussowitsch   Calling sequence:
2178a1cb98faSBarry Smith .vb
2179a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2180a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2181a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2182a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2183a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2184a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2185a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2186a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2187a1cb98faSBarry Smith        PetscSectionSetUp(section);
2188a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2189a1cb98faSBarry Smith        PetscSectionDestroy(&section);
2190a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2191a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2192a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2193a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2194a1cb98faSBarry Smith        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2195a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2196a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2197a1cb98faSBarry Smith        DMDestroy(&dm);
2198a1cb98faSBarry Smith .ve
21993e97647fSksagiyam 
22001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
22013e97647fSksagiyam @*/
2202d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2203d71ae5a4SJacob Faibussowitsch {
22043e97647fSksagiyam   PetscBool ishdf5;
22053e97647fSksagiyam 
22063e97647fSksagiyam   PetscFunctionBegin;
22073e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22083e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22093e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
22103e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
22113e97647fSksagiyam   /* Check consistency */
22123e97647fSksagiyam   {
22133e97647fSksagiyam     PetscSection section;
22143e97647fSksagiyam     PetscBool    includesConstraints;
22153e97647fSksagiyam     PetscInt     m, m1;
22163e97647fSksagiyam 
22179566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
22189566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
22199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
22209566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
22219566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
222263a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
22233e97647fSksagiyam   }
22249566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
22259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
22263e97647fSksagiyam   if (ishdf5) {
22273e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
22289566063dSJacob Faibussowitsch     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
22293e97647fSksagiyam #else
22303e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
22313e97647fSksagiyam #endif
22323e97647fSksagiyam   }
22339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
22343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22353e97647fSksagiyam }
22363e97647fSksagiyam 
22373e97647fSksagiyam /*@
22383e97647fSksagiyam   DMPlexLocalVectorView - Saves a local vector
22393e97647fSksagiyam 
224020f4b53cSBarry Smith   Collective
22413e97647fSksagiyam 
22423e97647fSksagiyam   Input Parameters:
2243a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2244a1cb98faSBarry Smith . viewer    - The `PetscViewer` to save data with
224520f4b53cSBarry Smith . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm`
22463e97647fSksagiyam - vec       - The local vector to be saved
22473e97647fSksagiyam 
22483e97647fSksagiyam   Level: advanced
22493e97647fSksagiyam 
2250a1cb98faSBarry Smith   Note:
225120f4b53cSBarry 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.
22523e97647fSksagiyam 
225360225df5SJacob Faibussowitsch   Calling sequence:
2254a1cb98faSBarry Smith .vb
2255a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2256a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2257a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2258a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2259a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2260a1cb98faSBarry Smith        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2261a1cb98faSBarry Smith        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2262a1cb98faSBarry Smith        PetscSectionSetChart(section, pStart, pEnd);
2263a1cb98faSBarry Smith        PetscSectionSetUp(section);
2264a1cb98faSBarry Smith        DMSetLocalSection(sectiondm, section);
2265a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2266a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2267a1cb98faSBarry Smith        DMPlexTopologyView(dm, viewer);
2268a1cb98faSBarry Smith        DMPlexSectionView(dm, viewer, sectiondm);
2269a1cb98faSBarry Smith        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2270a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2271a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2272a1cb98faSBarry Smith        DMDestroy(&dm);
2273a1cb98faSBarry Smith .ve
22743e97647fSksagiyam 
22751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
22763e97647fSksagiyam @*/
2277d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2278d71ae5a4SJacob Faibussowitsch {
22793e97647fSksagiyam   PetscBool ishdf5;
22803e97647fSksagiyam 
22813e97647fSksagiyam   PetscFunctionBegin;
22823e97647fSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22833e97647fSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
22843e97647fSksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
22853e97647fSksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
22863e97647fSksagiyam   /* Check consistency */
22873e97647fSksagiyam   {
22883e97647fSksagiyam     PetscSection section;
22893e97647fSksagiyam     PetscBool    includesConstraints;
22903e97647fSksagiyam     PetscInt     m, m1;
22913e97647fSksagiyam 
22929566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
22939566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
22949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
22959566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
22969566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
229763a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
22983e97647fSksagiyam   }
22999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
23013e97647fSksagiyam   if (ishdf5) {
23023e97647fSksagiyam #if defined(PETSC_HAVE_HDF5)
23039566063dSJacob Faibussowitsch     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
23043e97647fSksagiyam #else
23053e97647fSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
23063e97647fSksagiyam #endif
23073e97647fSksagiyam   }
23089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
23093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23103e97647fSksagiyam }
23113e97647fSksagiyam 
2312d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2313d71ae5a4SJacob Faibussowitsch {
2314d4f5a9a0SVaclav Hapla   PetscBool ishdf5;
23152c40f234SMatthew G. Knepley 
23162c40f234SMatthew G. Knepley   PetscFunctionBegin;
23172c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23182c40f234SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23199566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2320d4f5a9a0SVaclav Hapla   if (ishdf5) {
23212c40f234SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
23229c48423bSVaclav Hapla     PetscViewerFormat format;
23239566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
23249c48423bSVaclav Hapla     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
23259566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2326509517efSVaclav Hapla     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
23279566063dSJacob Faibussowitsch       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
232898921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
23293ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
23302c40f234SMatthew G. Knepley #else
23312c40f234SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2332552f7358SJed Brown #endif
233398921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2334552f7358SJed Brown }
2335552f7358SJed Brown 
2336ea8e1828Sksagiyam /*@
2337a1cb98faSBarry Smith   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2338ea8e1828Sksagiyam 
233920f4b53cSBarry Smith   Collective
2340ea8e1828Sksagiyam 
2341ea8e1828Sksagiyam   Input Parameters:
2342a1cb98faSBarry Smith + dm     - The `DM` into which the topology is loaded
2343a1cb98faSBarry Smith - viewer - The `PetscViewer` for the saved topology
2344ea8e1828Sksagiyam 
23452fe279fdSBarry Smith   Output Parameter:
234620f4b53cSBarry 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
2347dec9e869Sksagiyam 
2348ea8e1828Sksagiyam   Level: advanced
2349ea8e1828Sksagiyam 
23501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2351a1cb98faSBarry Smith           `PetscViewer`, `PetscSF`
2352ea8e1828Sksagiyam @*/
2353d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2354d71ae5a4SJacob Faibussowitsch {
2355ea8e1828Sksagiyam   PetscBool ishdf5;
2356ea8e1828Sksagiyam 
2357ea8e1828Sksagiyam   PetscFunctionBegin;
2358ea8e1828Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2359ea8e1828Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
23604f572ea9SToby Isaac   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
23619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
23629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2363ea8e1828Sksagiyam   if (ishdf5) {
2364ea8e1828Sksagiyam #if defined(PETSC_HAVE_HDF5)
2365ea8e1828Sksagiyam     PetscViewerFormat format;
23669566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2367ea8e1828Sksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
23689566063dSJacob Faibussowitsch       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
236998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2370ea8e1828Sksagiyam #else
2371ea8e1828Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2372ea8e1828Sksagiyam #endif
2373ea8e1828Sksagiyam   }
23749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
23753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2376ea8e1828Sksagiyam }
2377ea8e1828Sksagiyam 
23783e701f1cSksagiyam /*@
2379a1cb98faSBarry Smith   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
23803e701f1cSksagiyam 
238120f4b53cSBarry Smith   Collective
23823e701f1cSksagiyam 
23833e701f1cSksagiyam   Input Parameters:
2384a1cb98faSBarry Smith + dm                   - The `DM` into which the coordinates are loaded
2385a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved coordinates
2386a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
23873e701f1cSksagiyam 
23883e701f1cSksagiyam   Level: advanced
23893e701f1cSksagiyam 
23901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2391a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
23923e701f1cSksagiyam @*/
2393d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2394d71ae5a4SJacob Faibussowitsch {
23953e701f1cSksagiyam   PetscBool ishdf5;
23963e701f1cSksagiyam 
23973e701f1cSksagiyam   PetscFunctionBegin;
23983e701f1cSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23993e701f1cSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2400c9ad657eSksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
24019566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24029566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
24033e701f1cSksagiyam   if (ishdf5) {
24043e701f1cSksagiyam #if defined(PETSC_HAVE_HDF5)
24053e701f1cSksagiyam     PetscViewerFormat format;
24069566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
24073e701f1cSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24089566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
240998921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
24103e701f1cSksagiyam #else
24113e701f1cSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
24123e701f1cSksagiyam #endif
24133e701f1cSksagiyam   }
24149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
24153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24163e701f1cSksagiyam }
24173e701f1cSksagiyam 
2418b08ad5deSksagiyam /*@
2419a1cb98faSBarry Smith   DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2420b08ad5deSksagiyam 
242120f4b53cSBarry Smith   Collective
2422b08ad5deSksagiyam 
2423b08ad5deSksagiyam   Input Parameters:
2424a1cb98faSBarry Smith + dm                   - The `DM` into which the labels are loaded
2425a1cb98faSBarry Smith . viewer               - The `PetscViewer` for the saved labels
242620f4b53cSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2427b08ad5deSksagiyam 
2428b08ad5deSksagiyam   Level: advanced
2429b08ad5deSksagiyam 
2430a1cb98faSBarry Smith   Note:
2431a1cb98faSBarry Smith   The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs.
2432e6368b79SVaclav Hapla 
24331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2434a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
2435b08ad5deSksagiyam @*/
2436d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2437d71ae5a4SJacob Faibussowitsch {
2438b08ad5deSksagiyam   PetscBool ishdf5;
2439b08ad5deSksagiyam 
2440b08ad5deSksagiyam   PetscFunctionBegin;
2441b08ad5deSksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2442b08ad5deSksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2443e6368b79SVaclav Hapla   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
24449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
24459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2446b08ad5deSksagiyam   if (ishdf5) {
2447b08ad5deSksagiyam #if defined(PETSC_HAVE_HDF5)
2448b08ad5deSksagiyam     PetscViewerFormat format;
2449b08ad5deSksagiyam 
24509566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2451b08ad5deSksagiyam     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
24529566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
245398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2454b08ad5deSksagiyam #else
2455b08ad5deSksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2456b08ad5deSksagiyam #endif
2457b08ad5deSksagiyam   }
24589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
24593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2460b08ad5deSksagiyam }
2461b08ad5deSksagiyam 
2462f84dd6b4Sksagiyam /*@
2463a1cb98faSBarry Smith   DMPlexSectionLoad - Loads section into a `DMPLEX`
2464f84dd6b4Sksagiyam 
246520f4b53cSBarry Smith   Collective
2466f84dd6b4Sksagiyam 
2467f84dd6b4Sksagiyam   Input Parameters:
2468a1cb98faSBarry Smith + dm                   - The `DM` that represents the topology
2469a1cb98faSBarry Smith . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
2470a1cb98faSBarry Smith . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated
2471a1cb98faSBarry Smith - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2472f84dd6b4Sksagiyam 
2473a4e35b19SJacob Faibussowitsch   Output Parameters:
247420f4b53cSBarry 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)
247520f4b53cSBarry 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)
2476f84dd6b4Sksagiyam 
2477f84dd6b4Sksagiyam   Level: advanced
2478f84dd6b4Sksagiyam 
2479f84dd6b4Sksagiyam   Notes:
248020f4b53cSBarry 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.
2481f84dd6b4Sksagiyam 
248220f4b53cSBarry 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.
2483f84dd6b4Sksagiyam 
248420f4b53cSBarry 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.
2485f84dd6b4Sksagiyam 
2486f84dd6b4Sksagiyam   Example using 2 processes:
2487a1cb98faSBarry Smith .vb
2488a1cb98faSBarry Smith   NX (number of points on dm): 4
2489a1cb98faSBarry Smith   sectionA                   : the on-disk section
2490a1cb98faSBarry Smith   vecA                       : a vector associated with sectionA
2491a1cb98faSBarry Smith   sectionB                   : sectiondm's local section constructed in this function
2492a1cb98faSBarry Smith   vecB (local)               : a vector associated with sectiondm's local section
2493a1cb98faSBarry Smith   vecB (global)              : a vector associated with sectiondm's global section
2494f84dd6b4Sksagiyam 
2495a1cb98faSBarry Smith                                      rank 0    rank 1
2496a1cb98faSBarry Smith   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2497a1cb98faSBarry Smith   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2498a1cb98faSBarry Smith   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2499a1cb98faSBarry Smith   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2500a1cb98faSBarry Smith   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2501a1cb98faSBarry Smith   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2502a1cb98faSBarry Smith   sectionB->atlasDof             :     1 0 1 | 1 3
2503a1cb98faSBarry Smith   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2504a1cb98faSBarry Smith   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2505a1cb98faSBarry Smith   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2506a1cb98faSBarry Smith .ve
2507a1cb98faSBarry Smith   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2508a1cb98faSBarry Smith 
25091cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2510f84dd6b4Sksagiyam @*/
2511d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2512d71ae5a4SJacob Faibussowitsch {
2513f84dd6b4Sksagiyam   PetscBool ishdf5;
2514f84dd6b4Sksagiyam 
2515f84dd6b4Sksagiyam   PetscFunctionBegin;
2516f84dd6b4Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2517f84dd6b4Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2518f84dd6b4Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2519f84dd6b4Sksagiyam   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
25204f572ea9SToby Isaac   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
25214f572ea9SToby Isaac   if (localDofSF) PetscAssertPointer(localDofSF, 6);
25229566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2524f84dd6b4Sksagiyam   if (ishdf5) {
2525f84dd6b4Sksagiyam #if defined(PETSC_HAVE_HDF5)
25269566063dSJacob Faibussowitsch     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2527f84dd6b4Sksagiyam #else
2528f84dd6b4Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2529f84dd6b4Sksagiyam #endif
2530f84dd6b4Sksagiyam   }
25319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
25323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2533f84dd6b4Sksagiyam }
2534f84dd6b4Sksagiyam 
25358be3dfe1Sksagiyam /*@
25368be3dfe1Sksagiyam   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
25378be3dfe1Sksagiyam 
253820f4b53cSBarry Smith   Collective
25398be3dfe1Sksagiyam 
25408be3dfe1Sksagiyam   Input Parameters:
2541a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2542a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
2543a1cb98faSBarry Smith . sectiondm - The `DM` that contains the global section on which vec is defined
2544a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
25458be3dfe1Sksagiyam - vec       - The global vector to set values of
25468be3dfe1Sksagiyam 
25478be3dfe1Sksagiyam   Level: advanced
25488be3dfe1Sksagiyam 
25498be3dfe1Sksagiyam   Notes:
2550a1cb98faSBarry 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.
25518be3dfe1Sksagiyam 
255260225df5SJacob Faibussowitsch   Calling sequence:
2553a1cb98faSBarry Smith .vb
2554a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2555a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2556a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2557a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2558a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2559a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2560a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2561a1cb98faSBarry Smith        DMGetGlobalVector(sectiondm, &vec);
2562a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2563a1cb98faSBarry Smith        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2564a1cb98faSBarry Smith        DMRestoreGlobalVector(sectiondm, &vec);
2565a1cb98faSBarry Smith        PetscSFDestroy(&gsf);
2566a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2567a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2568a1cb98faSBarry Smith        DMDestroy(&dm);
2569a1cb98faSBarry Smith .ve
25708be3dfe1Sksagiyam 
25711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2572a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
25738be3dfe1Sksagiyam @*/
2574d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2575d71ae5a4SJacob Faibussowitsch {
25768be3dfe1Sksagiyam   PetscBool ishdf5;
25778be3dfe1Sksagiyam 
25788be3dfe1Sksagiyam   PetscFunctionBegin;
25798be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25808be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
25818be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
25828be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
25838be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
25848be3dfe1Sksagiyam   /* Check consistency */
25858be3dfe1Sksagiyam   {
25868be3dfe1Sksagiyam     PetscSection section;
25878be3dfe1Sksagiyam     PetscBool    includesConstraints;
25888be3dfe1Sksagiyam     PetscInt     m, m1;
25898be3dfe1Sksagiyam 
25909566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
25919566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(sectiondm, &section));
25929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
25939566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
25949566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
259563a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
25968be3dfe1Sksagiyam   }
25979566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
25998be3dfe1Sksagiyam   if (ishdf5) {
26008be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
26019566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
26028be3dfe1Sksagiyam #else
26038be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
26048be3dfe1Sksagiyam #endif
26058be3dfe1Sksagiyam   }
26069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
26073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26088be3dfe1Sksagiyam }
26098be3dfe1Sksagiyam 
26108be3dfe1Sksagiyam /*@
26118be3dfe1Sksagiyam   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
26128be3dfe1Sksagiyam 
261320f4b53cSBarry Smith   Collective
26148be3dfe1Sksagiyam 
26158be3dfe1Sksagiyam   Input Parameters:
2616a1cb98faSBarry Smith + dm        - The `DM` that represents the topology
2617a1cb98faSBarry Smith . viewer    - The `PetscViewer` that represents the on-disk vector data
2618a1cb98faSBarry Smith . sectiondm - The `DM` that contains the local section on which vec is defined
2619a1cb98faSBarry Smith . sf        - The `PetscSF` that migrates the on-disk vector data into vec
26208be3dfe1Sksagiyam - vec       - The local vector to set values of
26218be3dfe1Sksagiyam 
26228be3dfe1Sksagiyam   Level: advanced
26238be3dfe1Sksagiyam 
26248be3dfe1Sksagiyam   Notes:
262520f4b53cSBarry 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.
26268be3dfe1Sksagiyam 
262760225df5SJacob Faibussowitsch   Calling sequence:
2628a1cb98faSBarry Smith .vb
2629a1cb98faSBarry Smith        DMCreate(PETSC_COMM_WORLD, &dm);
2630a1cb98faSBarry Smith        DMSetType(dm, DMPLEX);
2631a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2632a1cb98faSBarry Smith        DMPlexTopologyLoad(dm, viewer, &sfX);
2633a1cb98faSBarry Smith        DMClone(dm, &sectiondm);
2634a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2635a1cb98faSBarry Smith        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2636a1cb98faSBarry Smith        DMGetLocalVector(sectiondm, &vec);
2637a1cb98faSBarry Smith        PetscObjectSetName((PetscObject)vec, "vec_name");
2638a1cb98faSBarry Smith        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2639a1cb98faSBarry Smith        DMRestoreLocalVector(sectiondm, &vec);
2640a1cb98faSBarry Smith        PetscSFDestroy(&lsf);
2641a1cb98faSBarry Smith        PetscSFDestroy(&sfX);
2642a1cb98faSBarry Smith        DMDestroy(&sectiondm);
2643a1cb98faSBarry Smith        DMDestroy(&dm);
2644a1cb98faSBarry Smith .ve
26458be3dfe1Sksagiyam 
26461cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2647a1cb98faSBarry Smith           `PetscSF`, `PetscViewer`
26488be3dfe1Sksagiyam @*/
2649d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2650d71ae5a4SJacob Faibussowitsch {
26518be3dfe1Sksagiyam   PetscBool ishdf5;
26528be3dfe1Sksagiyam 
26538be3dfe1Sksagiyam   PetscFunctionBegin;
26548be3dfe1Sksagiyam   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
26558be3dfe1Sksagiyam   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
26568be3dfe1Sksagiyam   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
26578be3dfe1Sksagiyam   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
26588be3dfe1Sksagiyam   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
26598be3dfe1Sksagiyam   /* Check consistency */
26608be3dfe1Sksagiyam   {
26618be3dfe1Sksagiyam     PetscSection section;
26628be3dfe1Sksagiyam     PetscBool    includesConstraints;
26638be3dfe1Sksagiyam     PetscInt     m, m1;
26648be3dfe1Sksagiyam 
26659566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(vec, &m1));
26669566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(sectiondm, &section));
26679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
26689566063dSJacob Faibussowitsch     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
26699566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
267063a3b9bcSJacob Faibussowitsch     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
26718be3dfe1Sksagiyam   }
26729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
26739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
26748be3dfe1Sksagiyam   if (ishdf5) {
26758be3dfe1Sksagiyam #if defined(PETSC_HAVE_HDF5)
26769566063dSJacob Faibussowitsch     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
26778be3dfe1Sksagiyam #else
26788be3dfe1Sksagiyam     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
26798be3dfe1Sksagiyam #endif
26808be3dfe1Sksagiyam   }
26819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
26823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26838be3dfe1Sksagiyam }
26848be3dfe1Sksagiyam 
2685d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Plex(DM dm)
2686d71ae5a4SJacob Faibussowitsch {
2687552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2688552f7358SJed Brown 
2689552f7358SJed Brown   PetscFunctionBegin;
26909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
26919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
26929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
26939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
26946c51210dSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL));
26952e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
26962e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
26972e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
26982e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
26996bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
27006bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2701d02c7345SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSectionGetDefault_C", NULL));
2702d02c7345SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSectionSetDefault_C", NULL));
2703c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2704c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2705d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2706d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
27075f06a3ddSJed Brown   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
27083ba16761SJacob Faibussowitsch   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
27099566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->coneSection));
27109566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->cones));
27119566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->coneOrientations));
27129566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
27139566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
27149566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
271521027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
27169f4ada15SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&mesh->tr));
27179566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->tetgenOpts));
27189566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->triangleOpts));
27199566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->transformType));
27201d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
27219566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
27229566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&mesh->subpointMap));
27239566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->subpointIS));
27249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
27259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->globalCellNumbers));
27264e2e9504SJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.face_sf));
27276725e60dSJed Brown   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
27286725e60dSJed Brown   PetscCall(ISDestroy(&mesh->periodic.periodic_points));
27299566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
27309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&mesh->anchorIS));
27319566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
27329566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->parents));
27339566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->childIDs));
27349566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
27359566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
27369566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
27379566063dSJacob Faibussowitsch   PetscCall(PetscGridHashDestroy(&mesh->lbox));
27389566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->neighbors));
27399566063dSJacob Faibussowitsch   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2740552f7358SJed Brown   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
27419566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh));
27423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2743552f7358SJed Brown }
2744552f7358SJed Brown 
2745d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2746d71ae5a4SJacob Faibussowitsch {
2747d02c7345SMatthew G. Knepley   PetscSection           sectionGlobal, sectionLocal;
2748acd755d7SMatthew G. Knepley   PetscInt               bs = -1, mbs;
27499fca9976SJed Brown   PetscInt               localSize, localStart = 0;
2750837628f4SStefano Zampini   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2751b412c318SBarry Smith   MatType                mtype;
27521428887cSShri Abhyankar   ISLocalToGlobalMapping ltog;
2753552f7358SJed Brown 
2754552f7358SJed Brown   PetscFunctionBegin;
27559566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2756b412c318SBarry Smith   mtype = dm->mattype;
2757d02c7345SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &sectionLocal));
27589566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
27599566063dSJacob Faibussowitsch   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
27609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
27619fca9976SJed Brown   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
27629566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
27639566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
27649566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, mtype));
27659566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*J));
27669566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(*J, &mbs));
2767acd755d7SMatthew G. Knepley   if (mbs > 1) bs = mbs;
27689566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
27699566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
27709566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
27719566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
27729566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
27739566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
27749566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
27759566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2776552f7358SJed Brown   if (!isShell) {
2777837628f4SStefano Zampini     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
27789fca9976SJed Brown     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2779863027abSJed Brown     PetscInt  pStart, pEnd, p, dof, cdof, num_fields;
2780552f7358SJed Brown 
27819566063dSJacob Faibussowitsch     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
27829fca9976SJed Brown 
27839fca9976SJed Brown     PetscCall(PetscCalloc1(localSize, &pblocks));
27849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2785863027abSJed Brown     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2786e432b41dSStefano Zampini     for (p = pStart; p < pEnd; ++p) {
2787863027abSJed Brown       switch (dm->blocking_type) {
27880e762ea3SJed Brown       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
27899fca9976SJed Brown         PetscInt bdof, offset;
2790a9d99c84SMatthew G. Knepley 
27919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
27929fca9976SJed Brown         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
27939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2794d02c7345SMatthew G. Knepley         for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof;
2795d02c7345SMatthew G. Knepley         // Signal block concatenation
2796d02c7345SMatthew G. Knepley         if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof);
27971d17a0a3SMatthew G. Knepley         dof  = dof < 0 ? -(dof + 1) : dof;
27981d17a0a3SMatthew G. Knepley         bdof = cdof && (dof - cdof) ? 1 : dof;
27991d17a0a3SMatthew G. Knepley         if (dof) {
28009371c9d4SSatish Balay           if (bs < 0) {
28019371c9d4SSatish Balay             bs = bdof;
28029371c9d4SSatish Balay           } else if (bs != bdof) {
28039371c9d4SSatish Balay             bs = 1;
28049371c9d4SSatish Balay           }
2805552f7358SJed Brown         }
2806863027abSJed Brown       } break;
2807863027abSJed Brown       case DM_BLOCKING_FIELD_NODE: {
2808863027abSJed Brown         for (PetscInt field = 0; field < num_fields; field++) {
2809863027abSJed Brown           PetscInt num_comp, bdof, offset;
2810863027abSJed Brown           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2811863027abSJed Brown           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2812863027abSJed Brown           if (dof < 0) continue;
2813863027abSJed Brown           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2814863027abSJed Brown           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2815863027abSJed 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);
2816863027abSJed Brown           PetscInt num_nodes = dof / num_comp;
2817863027abSJed Brown           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2818863027abSJed Brown           // Handle possibly constant block size (unlikely)
2819863027abSJed Brown           bdof = cdof && (dof - cdof) ? 1 : dof;
2820863027abSJed Brown           if (dof) {
2821863027abSJed Brown             if (bs < 0) {
2822863027abSJed Brown               bs = bdof;
2823863027abSJed Brown             } else if (bs != bdof) {
2824863027abSJed Brown               bs = 1;
2825863027abSJed Brown             }
2826863027abSJed Brown           }
2827863027abSJed Brown         }
2828863027abSJed Brown       } break;
2829863027abSJed Brown       }
28302a28c762SMatthew G Knepley     }
28312a28c762SMatthew G Knepley     /* Must have same blocksize on all procs (some might have no points) */
2832e432b41dSStefano Zampini     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2833e432b41dSStefano Zampini     bsLocal[1] = bs;
28349566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2835e432b41dSStefano Zampini     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2836e432b41dSStefano Zampini     else bs = bsMinMax[0];
28376fd5c86aSStefano Zampini     bs = PetscMax(1, bs);
28389566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
28390682b8bbSJed Brown     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
28409566063dSJacob Faibussowitsch       PetscCall(MatSetBlockSize(*J, bs));
28419566063dSJacob Faibussowitsch       PetscCall(MatSetUp(*J));
28420682b8bbSJed Brown     } else {
28439566063dSJacob Faibussowitsch       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
28449566063dSJacob Faibussowitsch       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
28459566063dSJacob Faibussowitsch       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2846552f7358SJed Brown     }
28479fca9976SJed Brown     { // Consolidate blocks
28489fca9976SJed Brown       PetscInt nblocks = 0;
28499fca9976SJed Brown       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
28509fca9976SJed Brown         if (pblocks[i] == 0) continue;
2851d02c7345SMatthew G. Knepley         // Negative block size indicates the blocks should be concatenated
2852d02c7345SMatthew G. Knepley         if (pblocks[i] < 0) {
2853d02c7345SMatthew G. Knepley           pblocks[i] = -pblocks[i];
2854d02c7345SMatthew G. Knepley           pblocks[nblocks - 1] += pblocks[i];
2855d02c7345SMatthew G. Knepley         } else {
28569fca9976SJed Brown           pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2857d02c7345SMatthew G. Knepley         }
2858ad540459SPierre 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]);
28599fca9976SJed Brown       }
28609fca9976SJed Brown       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
28619fca9976SJed Brown     }
28629fca9976SJed Brown     PetscCall(PetscFree(pblocks));
2863aa0f6e3cSJed Brown   }
28649566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*J, dm));
28653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2866552f7358SJed Brown }
2867552f7358SJed Brown 
28687cd05799SMatthew G. Knepley /*@
2869a8f00d21SMatthew G. Knepley   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2870be36d101SStefano Zampini 
2871a1cb98faSBarry Smith   Not Collective
2872be36d101SStefano Zampini 
2873be36d101SStefano Zampini   Input Parameter:
287460225df5SJacob Faibussowitsch . dm - The `DMPLEX`
2875be36d101SStefano Zampini 
28762fe279fdSBarry Smith   Output Parameter:
2877be36d101SStefano Zampini . subsection - The subdomain section
2878be36d101SStefano Zampini 
2879be36d101SStefano Zampini   Level: developer
2880be36d101SStefano Zampini 
28811cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
28827cd05799SMatthew G. Knepley @*/
2883d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2884d71ae5a4SJacob Faibussowitsch {
2885be36d101SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
2886be36d101SStefano Zampini 
2887be36d101SStefano Zampini   PetscFunctionBegin;
2888be36d101SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2889be36d101SStefano Zampini   if (!mesh->subdomainSection) {
2890be36d101SStefano Zampini     PetscSection section;
2891be36d101SStefano Zampini     PetscSF      sf;
2892be36d101SStefano Zampini 
28939566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
28949566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
28959566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
28969566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
2897be36d101SStefano Zampini   }
2898be36d101SStefano Zampini   *subsection = mesh->subdomainSection;
28993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2900be36d101SStefano Zampini }
2901be36d101SStefano Zampini 
2902552f7358SJed Brown /*@
290320f4b53cSBarry Smith   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
2904552f7358SJed Brown 
2905a1cb98faSBarry Smith   Not Collective
2906552f7358SJed Brown 
2907552f7358SJed Brown   Input Parameter:
290860225df5SJacob Faibussowitsch . dm - The `DMPLEX`
2909552f7358SJed Brown 
2910552f7358SJed Brown   Output Parameters:
2911552f7358SJed Brown + pStart - The first mesh point
2912552f7358SJed Brown - pEnd   - The upper bound for mesh points
2913552f7358SJed Brown 
2914552f7358SJed Brown   Level: beginner
2915552f7358SJed Brown 
29161cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2917552f7358SJed Brown @*/
2918d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2919d71ae5a4SJacob Faibussowitsch {
2920552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2921552f7358SJed Brown 
2922552f7358SJed Brown   PetscFunctionBegin;
2923552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
29249f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
29259f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
29263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2927552f7358SJed Brown }
2928552f7358SJed Brown 
2929552f7358SJed Brown /*@
293020f4b53cSBarry Smith   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
2931552f7358SJed Brown 
2932a1cb98faSBarry Smith   Not Collective
2933552f7358SJed Brown 
2934552f7358SJed Brown   Input Parameters:
293560225df5SJacob Faibussowitsch + dm     - The `DMPLEX`
2936552f7358SJed Brown . pStart - The first mesh point
2937552f7358SJed Brown - pEnd   - The upper bound for mesh points
2938552f7358SJed Brown 
2939552f7358SJed Brown   Level: beginner
2940552f7358SJed Brown 
29411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2942552f7358SJed Brown @*/
2943d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2944d71ae5a4SJacob Faibussowitsch {
2945552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2946552f7358SJed Brown 
2947552f7358SJed Brown   PetscFunctionBegin;
2948552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
29499566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
29509566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
295121027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
29523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2953552f7358SJed Brown }
2954552f7358SJed Brown 
2955552f7358SJed Brown /*@
2956eaf898f9SPatrick Sanan   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2957552f7358SJed Brown 
2958a1cb98faSBarry Smith   Not Collective
2959552f7358SJed Brown 
2960552f7358SJed Brown   Input Parameters:
296160225df5SJacob Faibussowitsch + dm - The `DMPLEX`
2962a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
2963552f7358SJed Brown 
2964552f7358SJed Brown   Output Parameter:
296520f4b53cSBarry Smith . size - The cone size for point `p`
2966552f7358SJed Brown 
2967552f7358SJed Brown   Level: beginner
2968552f7358SJed Brown 
29691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2970552f7358SJed Brown @*/
2971d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2972d71ae5a4SJacob Faibussowitsch {
2973552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
2974552f7358SJed Brown 
2975552f7358SJed Brown   PetscFunctionBegin;
2976552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
29774f572ea9SToby Isaac   PetscAssertPointer(size, 3);
29789f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
29799f4ada15SMatthew G. Knepley   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
29803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2981552f7358SJed Brown }
2982552f7358SJed Brown 
2983552f7358SJed Brown /*@
2984eaf898f9SPatrick Sanan   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2985552f7358SJed Brown 
2986a1cb98faSBarry Smith   Not Collective
2987552f7358SJed Brown 
2988552f7358SJed Brown   Input Parameters:
298960225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
2990a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
299120f4b53cSBarry Smith - size - The cone size for point `p`
2992552f7358SJed Brown 
2993552f7358SJed Brown   Level: beginner
2994552f7358SJed Brown 
2995a1cb98faSBarry Smith   Note:
2996a1cb98faSBarry Smith   This should be called after `DMPlexSetChart()`.
2997a1cb98faSBarry Smith 
29981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2999552f7358SJed Brown @*/
3000d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
3001d71ae5a4SJacob Faibussowitsch {
3002552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3003552f7358SJed Brown 
3004552f7358SJed Brown   PetscFunctionBegin;
3005552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30069f4ada15SMatthew G. Knepley   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
30079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
30083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3009552f7358SJed Brown }
3010552f7358SJed Brown 
3011552f7358SJed Brown /*@C
3012eaf898f9SPatrick Sanan   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
3013552f7358SJed Brown 
3014a1cb98faSBarry Smith   Not Collective
3015552f7358SJed Brown 
3016552f7358SJed Brown   Input Parameters:
3017a1cb98faSBarry Smith + dm - The `DMPLEX`
3018a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3019552f7358SJed Brown 
3020552f7358SJed Brown   Output Parameter:
302120f4b53cSBarry Smith . cone - An array of points which are on the in-edges for point `p`
3022552f7358SJed Brown 
3023552f7358SJed Brown   Level: beginner
3024552f7358SJed Brown 
302560225df5SJacob Faibussowitsch   Fortran Notes:
3026a1cb98faSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
3027a1cb98faSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
30283813dfbdSMatthew G Knepley 
30291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
3030552f7358SJed Brown @*/
3031d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
3032d71ae5a4SJacob Faibussowitsch {
3033552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3034552f7358SJed Brown   PetscInt off;
3035552f7358SJed Brown 
3036552f7358SJed Brown   PetscFunctionBegin;
3037552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30384f572ea9SToby Isaac   PetscAssertPointer(cone, 3);
30399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
30408e3a54c0SPierre Jolivet   *cone = PetscSafePointerPlusOffset(mesh->cones, off);
30413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3042552f7358SJed Brown }
3043552f7358SJed Brown 
30440ce7577fSVaclav Hapla /*@C
30450ce7577fSVaclav Hapla   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
30460ce7577fSVaclav Hapla 
3047a1cb98faSBarry Smith   Not Collective
30480ce7577fSVaclav Hapla 
30490ce7577fSVaclav Hapla   Input Parameters:
3050a1cb98faSBarry Smith + dm - The `DMPLEX`
3051a1cb98faSBarry Smith - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
30520ce7577fSVaclav Hapla 
3053d8d19677SJose E. Roman   Output Parameters:
305420f4b53cSBarry Smith + pConesSection - `PetscSection` describing the layout of `pCones`
305520f4b53cSBarry Smith - pCones        - An array of points which are on the in-edges for the point set `p`
30560ce7577fSVaclav Hapla 
30570ce7577fSVaclav Hapla   Level: intermediate
30580ce7577fSVaclav Hapla 
30591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
30600ce7577fSVaclav Hapla @*/
3061d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
3062d71ae5a4SJacob Faibussowitsch {
30630ce7577fSVaclav Hapla   PetscSection cs, newcs;
30640ce7577fSVaclav Hapla   PetscInt    *cones;
30650ce7577fSVaclav Hapla   PetscInt    *newarr = NULL;
30660ce7577fSVaclav Hapla   PetscInt     n;
30670ce7577fSVaclav Hapla 
30680ce7577fSVaclav Hapla   PetscFunctionBegin;
30699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
30709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &cs));
30719566063dSJacob Faibussowitsch   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
30720ce7577fSVaclav Hapla   if (pConesSection) *pConesSection = newcs;
30730ce7577fSVaclav Hapla   if (pCones) {
30749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newcs, &n));
30759566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
30760ce7577fSVaclav Hapla   }
30773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30780ce7577fSVaclav Hapla }
30790ce7577fSVaclav Hapla 
3080af9eab45SVaclav Hapla /*@
3081af9eab45SVaclav Hapla   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
3082d4636a37SVaclav Hapla 
3083a1cb98faSBarry Smith   Not Collective
3084d4636a37SVaclav Hapla 
3085d4636a37SVaclav Hapla   Input Parameters:
3086a1cb98faSBarry Smith + dm     - The `DMPLEX`
3087a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3088d4636a37SVaclav Hapla 
3089d4636a37SVaclav Hapla   Output Parameter:
3090af9eab45SVaclav Hapla . expandedPoints - An array of vertices recursively expanded from input points
3091d4636a37SVaclav Hapla 
3092d4636a37SVaclav Hapla   Level: advanced
3093d4636a37SVaclav Hapla 
3094af9eab45SVaclav Hapla   Notes:
309520f4b53cSBarry Smith   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
3096af9eab45SVaclav Hapla 
3097a1cb98faSBarry Smith   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
3098a1cb98faSBarry Smith 
30991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
3100a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`
3101d4636a37SVaclav Hapla @*/
3102d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
3103d71ae5a4SJacob Faibussowitsch {
3104af9eab45SVaclav Hapla   IS      *expandedPointsAll;
3105af9eab45SVaclav Hapla   PetscInt depth;
3106d4636a37SVaclav Hapla 
3107d4636a37SVaclav Hapla   PetscFunctionBegin;
3108af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3109af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
31104f572ea9SToby Isaac   PetscAssertPointer(expandedPoints, 3);
31119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
3112af9eab45SVaclav Hapla   *expandedPoints = expandedPointsAll[0];
31139566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
31149566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
31153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3116af9eab45SVaclav Hapla }
3117af9eab45SVaclav Hapla 
3118af9eab45SVaclav Hapla /*@
3119af9eab45SVaclav 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).
3120af9eab45SVaclav Hapla 
3121a1cb98faSBarry Smith   Not Collective
3122af9eab45SVaclav Hapla 
3123af9eab45SVaclav Hapla   Input Parameters:
3124a1cb98faSBarry Smith + dm     - The `DMPLEX`
3125a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3126af9eab45SVaclav Hapla 
3127d8d19677SJose E. Roman   Output Parameters:
3128a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3129af9eab45SVaclav Hapla . expandedPoints - (optional) An array of index sets with recursively expanded cones
3130af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3131af9eab45SVaclav Hapla 
3132af9eab45SVaclav Hapla   Level: advanced
3133af9eab45SVaclav Hapla 
3134af9eab45SVaclav Hapla   Notes:
3135a1cb98faSBarry Smith   Like `DMPlexGetConeTuple()` but recursive.
3136af9eab45SVaclav Hapla 
3137a4e35b19SJacob 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.
3138af9eab45SVaclav Hapla   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
3139af9eab45SVaclav Hapla 
3140a4e35b19SJacob 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\:
3141a4e35b19SJacob Faibussowitsch   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
3142a4e35b19SJacob Faibussowitsch   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
3143af9eab45SVaclav Hapla 
31441cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3145a1cb98faSBarry Smith           `DMPlexGetDepth()`, `PetscSection`, `IS`
3146af9eab45SVaclav Hapla @*/
3147d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3148d71ae5a4SJacob Faibussowitsch {
3149af9eab45SVaclav Hapla   const PetscInt *arr0 = NULL, *cone = NULL;
3150af9eab45SVaclav Hapla   PetscInt       *arr = NULL, *newarr = NULL;
3151af9eab45SVaclav Hapla   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
3152af9eab45SVaclav Hapla   IS             *expandedPoints_;
3153af9eab45SVaclav Hapla   PetscSection   *sections_;
3154af9eab45SVaclav Hapla 
3155af9eab45SVaclav Hapla   PetscFunctionBegin;
3156af9eab45SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3157af9eab45SVaclav Hapla   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
31584f572ea9SToby Isaac   if (depth) PetscAssertPointer(depth, 3);
31594f572ea9SToby Isaac   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
31604f572ea9SToby Isaac   if (sections) PetscAssertPointer(sections, 5);
31619566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(points, &n));
31629566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &arr0));
31639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
31649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
31659566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(depth_, &sections_));
3166af9eab45SVaclav Hapla   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
3167af9eab45SVaclav Hapla   for (d = depth_ - 1; d >= 0; d--) {
31689566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
31699566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
3170af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
31719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
3172af9eab45SVaclav Hapla       if (arr[i] >= start && arr[i] < end) {
31739566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
31749566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3175af9eab45SVaclav Hapla       } else {
31769566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3177af9eab45SVaclav Hapla       }
3178af9eab45SVaclav Hapla     }
31799566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(sections_[d]));
31809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
31819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newn, &newarr));
3182af9eab45SVaclav Hapla     for (i = 0; i < n; i++) {
31839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
31849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3185af9eab45SVaclav Hapla       if (cn > 1) {
31869566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
31879566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3188af9eab45SVaclav Hapla       } else {
3189af9eab45SVaclav Hapla         newarr[co] = arr[i];
3190af9eab45SVaclav Hapla       }
3191af9eab45SVaclav Hapla     }
31929566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3193af9eab45SVaclav Hapla     arr = newarr;
3194af9eab45SVaclav Hapla     n   = newn;
3195af9eab45SVaclav Hapla   }
31969566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &arr0));
3197af9eab45SVaclav Hapla   *depth = depth_;
3198af9eab45SVaclav Hapla   if (expandedPoints) *expandedPoints = expandedPoints_;
3199af9eab45SVaclav Hapla   else {
32009566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
32019566063dSJacob Faibussowitsch     PetscCall(PetscFree(expandedPoints_));
3202af9eab45SVaclav Hapla   }
3203af9eab45SVaclav Hapla   if (sections) *sections = sections_;
3204af9eab45SVaclav Hapla   else {
32059566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
32069566063dSJacob Faibussowitsch     PetscCall(PetscFree(sections_));
3207af9eab45SVaclav Hapla   }
32083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3209af9eab45SVaclav Hapla }
3210af9eab45SVaclav Hapla 
3211af9eab45SVaclav Hapla /*@
3212a1cb98faSBarry Smith   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3213af9eab45SVaclav Hapla 
3214a1cb98faSBarry Smith   Not Collective
3215af9eab45SVaclav Hapla 
3216af9eab45SVaclav Hapla   Input Parameters:
3217a1cb98faSBarry Smith + dm     - The `DMPLEX`
3218a1cb98faSBarry Smith - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3219af9eab45SVaclav Hapla 
3220d8d19677SJose E. Roman   Output Parameters:
3221a1cb98faSBarry Smith + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3222af9eab45SVaclav Hapla . expandedPoints - (optional) An array of recursively expanded cones
3223af9eab45SVaclav Hapla - sections       - (optional) An array of sections which describe mappings from points to their cone points
3224af9eab45SVaclav Hapla 
3225af9eab45SVaclav Hapla   Level: advanced
3226af9eab45SVaclav Hapla 
3227a1cb98faSBarry Smith   Note:
3228a1cb98faSBarry Smith   See `DMPlexGetConeRecursive()`
3229af9eab45SVaclav Hapla 
32301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3231a1cb98faSBarry Smith           `DMPlexGetDepth()`, `IS`, `PetscSection`
3232af9eab45SVaclav Hapla @*/
3233d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3234d71ae5a4SJacob Faibussowitsch {
3235af9eab45SVaclav Hapla   PetscInt d, depth_;
3236af9eab45SVaclav Hapla 
3237af9eab45SVaclav Hapla   PetscFunctionBegin;
32389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth_));
32391dca8a05SBarry Smith   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3240af9eab45SVaclav Hapla   if (depth) *depth = 0;
3241af9eab45SVaclav Hapla   if (expandedPoints) {
32429566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
32439566063dSJacob Faibussowitsch     PetscCall(PetscFree(*expandedPoints));
3244af9eab45SVaclav Hapla   }
3245af9eab45SVaclav Hapla   if (sections) {
32469566063dSJacob Faibussowitsch     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
32479566063dSJacob Faibussowitsch     PetscCall(PetscFree(*sections));
3248af9eab45SVaclav Hapla   }
32493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3250d4636a37SVaclav Hapla }
3251d4636a37SVaclav Hapla 
3252552f7358SJed Brown /*@
325392371b87SBarry 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
3254552f7358SJed Brown 
3255a1cb98faSBarry Smith   Not Collective
3256552f7358SJed Brown 
3257552f7358SJed Brown   Input Parameters:
325860225df5SJacob Faibussowitsch + dm   - The `DMPLEX`
3259a1cb98faSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
326020f4b53cSBarry Smith - cone - An array of points which are on the in-edges for point `p`
3261552f7358SJed Brown 
3262552f7358SJed Brown   Level: beginner
3263552f7358SJed Brown 
3264a1cb98faSBarry Smith   Note:
3265a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3266a1cb98faSBarry Smith 
32671cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3268552f7358SJed Brown @*/
3269d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3270d71ae5a4SJacob Faibussowitsch {
3271552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3272552f7358SJed Brown   PetscInt dof, off, c;
3273552f7358SJed Brown 
3274552f7358SJed Brown   PetscFunctionBegin;
3275552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
32774f572ea9SToby Isaac   if (dof) PetscAssertPointer(cone, 3);
32789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3279db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3280db485b19SStefano Zampini     PetscInt pStart, pEnd;
3281db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
328263a3b9bcSJacob 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);
3283552f7358SJed Brown     for (c = 0; c < dof; ++c) {
328463a3b9bcSJacob 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);
3285552f7358SJed Brown       mesh->cones[off + c] = cone[c];
3286552f7358SJed Brown     }
3287db485b19SStefano Zampini   } else {
3288db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3289db485b19SStefano Zampini   }
32903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3291552f7358SJed Brown }
3292552f7358SJed Brown 
3293552f7358SJed Brown /*@C
3294eaf898f9SPatrick Sanan   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3295552f7358SJed Brown 
3296a1cb98faSBarry Smith   Not Collective
3297552f7358SJed Brown 
3298552f7358SJed Brown   Input Parameters:
329960225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3300a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3301552f7358SJed Brown 
3302552f7358SJed Brown   Output Parameter:
330320f4b53cSBarry Smith . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
3304b5a892a1SMatthew G. Knepley                     integer giving the prescription for cone traversal.
3305552f7358SJed Brown 
3306552f7358SJed Brown   Level: beginner
3307552f7358SJed Brown 
3308a1cb98faSBarry Smith   Note:
3309b5a892a1SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3310b5a892a1SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3311a1cb98faSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3312b5a892a1SMatthew G. Knepley   with the identity.
3313b5a892a1SMatthew G. Knepley 
331460225df5SJacob Faibussowitsch   Fortran Notes:
3315a1cb98faSBarry Smith   You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3316a1cb98faSBarry Smith   `DMPlexRestoreConeOrientation()` is not needed/available in C.
33173813dfbdSMatthew G Knepley 
33181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3319552f7358SJed Brown @*/
3320d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3321d71ae5a4SJacob Faibussowitsch {
3322552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3323552f7358SJed Brown   PetscInt off;
3324552f7358SJed Brown 
3325552f7358SJed Brown   PetscFunctionBegin;
3326552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
332776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3328552f7358SJed Brown     PetscInt dof;
33299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
33304f572ea9SToby Isaac     if (dof) PetscAssertPointer(coneOrientation, 3);
3331552f7358SJed Brown   }
33329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
33330d644c17SKarl Rupp 
3334552f7358SJed Brown   *coneOrientation = &mesh->coneOrientations[off];
33353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3336552f7358SJed Brown }
3337552f7358SJed Brown 
3338552f7358SJed Brown /*@
3339eaf898f9SPatrick Sanan   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3340552f7358SJed Brown 
3341a1cb98faSBarry Smith   Not Collective
3342552f7358SJed Brown 
3343552f7358SJed Brown   Input Parameters:
334460225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3345a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3346b5a892a1SMatthew G. Knepley - coneOrientation - An array of orientations
3347b5a892a1SMatthew G. Knepley 
3348552f7358SJed Brown   Level: beginner
3349552f7358SJed Brown 
3350a1cb98faSBarry Smith   Notes:
3351a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3352a1cb98faSBarry Smith 
3353a1cb98faSBarry Smith   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3354a1cb98faSBarry Smith 
33551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3356552f7358SJed Brown @*/
3357d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3358d71ae5a4SJacob Faibussowitsch {
3359552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3360552f7358SJed Brown   PetscInt pStart, pEnd;
3361552f7358SJed Brown   PetscInt dof, off, c;
3362552f7358SJed Brown 
3363552f7358SJed Brown   PetscFunctionBegin;
3364552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
33664f572ea9SToby Isaac   if (dof) PetscAssertPointer(coneOrientation, 3);
33679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3368db485b19SStefano Zampini   if (PetscDefined(USE_DEBUG)) {
3369db485b19SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
337063a3b9bcSJacob 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);
3371552f7358SJed Brown     for (c = 0; c < dof; ++c) {
3372552f7358SJed Brown       PetscInt cdof, o = coneOrientation[c];
3373552f7358SJed Brown 
33749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
33751dca8a05SBarry 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);
3376552f7358SJed Brown       mesh->coneOrientations[off + c] = o;
3377552f7358SJed Brown     }
3378db485b19SStefano Zampini   } else {
3379db485b19SStefano Zampini     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3380db485b19SStefano Zampini   }
33813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3382552f7358SJed Brown }
3383552f7358SJed Brown 
33847cd05799SMatthew G. Knepley /*@
3385eaf898f9SPatrick Sanan   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
33867cd05799SMatthew G. Knepley 
3387a1cb98faSBarry Smith   Not Collective
33887cd05799SMatthew G. Knepley 
33897cd05799SMatthew G. Knepley   Input Parameters:
339060225df5SJacob Faibussowitsch + dm        - The `DMPLEX`
3391a1cb98faSBarry Smith . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
33927cd05799SMatthew G. Knepley . conePos   - The local index in the cone where the point should be put
33937cd05799SMatthew G. Knepley - conePoint - The mesh point to insert
33947cd05799SMatthew G. Knepley 
33957cd05799SMatthew G. Knepley   Level: beginner
33967cd05799SMatthew G. Knepley 
33971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
33987cd05799SMatthew G. Knepley @*/
3399d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3400d71ae5a4SJacob Faibussowitsch {
3401552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3402552f7358SJed Brown   PetscInt pStart, pEnd;
3403552f7358SJed Brown   PetscInt dof, off;
3404552f7358SJed Brown 
3405552f7358SJed Brown   PetscFunctionBegin;
3406552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3407a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
34089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
340963a3b9bcSJacob 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);
341063a3b9bcSJacob 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);
34119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
341263a3b9bcSJacob 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);
3413a03d55ffSStefano Zampini   }
3414a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3415552f7358SJed Brown   mesh->cones[off + conePos] = conePoint;
34163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3417552f7358SJed Brown }
3418552f7358SJed Brown 
34197cd05799SMatthew G. Knepley /*@
3420eaf898f9SPatrick Sanan   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
34217cd05799SMatthew G. Knepley 
3422a1cb98faSBarry Smith   Not Collective
34237cd05799SMatthew G. Knepley 
34247cd05799SMatthew G. Knepley   Input Parameters:
342560225df5SJacob Faibussowitsch + dm              - The `DMPLEX`
3426a1cb98faSBarry Smith . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
34277cd05799SMatthew G. Knepley . conePos         - The local index in the cone where the point should be put
34287cd05799SMatthew G. Knepley - coneOrientation - The point orientation to insert
34297cd05799SMatthew G. Knepley 
34307cd05799SMatthew G. Knepley   Level: beginner
34317cd05799SMatthew G. Knepley 
3432a1cb98faSBarry Smith   Note:
3433a1cb98faSBarry Smith   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3434b5a892a1SMatthew G. Knepley 
34351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
34367cd05799SMatthew G. Knepley @*/
3437d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3438d71ae5a4SJacob Faibussowitsch {
343977c88f5bSMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
344077c88f5bSMatthew G Knepley   PetscInt pStart, pEnd;
344177c88f5bSMatthew G Knepley   PetscInt dof, off;
344277c88f5bSMatthew G Knepley 
344377c88f5bSMatthew G Knepley   PetscFunctionBegin;
344477c88f5bSMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3445a03d55ffSStefano Zampini   if (PetscDefined(USE_DEBUG)) {
34469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
344763a3b9bcSJacob 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);
34489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
344963a3b9bcSJacob 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);
3450a03d55ffSStefano Zampini   }
3451a03d55ffSStefano Zampini   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
345277c88f5bSMatthew G Knepley   mesh->coneOrientations[off + conePos] = coneOrientation;
34533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
345477c88f5bSMatthew G Knepley }
345577c88f5bSMatthew G Knepley 
34569f4ada15SMatthew G. Knepley /*@C
34579f4ada15SMatthew G. Knepley   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
34589f4ada15SMatthew G. Knepley 
34599f4ada15SMatthew G. Knepley   Not collective
34609f4ada15SMatthew G. Knepley 
34619f4ada15SMatthew G. Knepley   Input Parameters:
34629f4ada15SMatthew G. Knepley + dm - The DMPlex
34639f4ada15SMatthew G. Knepley - p  - The point, which must lie in the chart set with DMPlexSetChart()
34649f4ada15SMatthew G. Knepley 
34659f4ada15SMatthew G. Knepley   Output Parameters:
346620f4b53cSBarry Smith + cone - An array of points which are on the in-edges for point `p`
346720f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
34689f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
34699f4ada15SMatthew G. Knepley 
34709f4ada15SMatthew G. Knepley   Level: beginner
34719f4ada15SMatthew G. Knepley 
34729f4ada15SMatthew G. Knepley   Notes:
34739f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
34749f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
347520f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
34769f4ada15SMatthew G. Knepley   with the identity.
34779f4ada15SMatthew G. Knepley 
34789f4ada15SMatthew G. Knepley   Fortran Notes:
347920f4b53cSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
348020f4b53cSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
34819f4ada15SMatthew G. Knepley 
34821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
34839f4ada15SMatthew G. Knepley @*/
34849f4ada15SMatthew G. Knepley PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
34859f4ada15SMatthew G. Knepley {
34869f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
34879f4ada15SMatthew G. Knepley 
34889f4ada15SMatthew G. Knepley   PetscFunctionBegin;
34899f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34909f4ada15SMatthew G. Knepley   if (mesh->tr) {
34919f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
34929f4ada15SMatthew G. Knepley   } else {
34939f4ada15SMatthew G. Knepley     PetscInt off;
34949f4ada15SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
34959f4ada15SMatthew G. Knepley       PetscInt dof;
34969f4ada15SMatthew G. Knepley       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
34979f4ada15SMatthew G. Knepley       if (dof) {
34984f572ea9SToby Isaac         if (cone) PetscAssertPointer(cone, 3);
34994f572ea9SToby Isaac         if (ornt) PetscAssertPointer(ornt, 4);
35009f4ada15SMatthew G. Knepley       }
35019f4ada15SMatthew G. Knepley     }
35029f4ada15SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
35038e3a54c0SPierre Jolivet     if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off);
35048e3a54c0SPierre Jolivet     if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off);
35059f4ada15SMatthew G. Knepley   }
35063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35079f4ada15SMatthew G. Knepley }
35089f4ada15SMatthew G. Knepley 
35099f4ada15SMatthew G. Knepley /*@C
35109f4ada15SMatthew G. Knepley   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG
35119f4ada15SMatthew G. Knepley 
351220f4b53cSBarry Smith   Not Collective
35139f4ada15SMatthew G. Knepley 
35149f4ada15SMatthew G. Knepley   Input Parameters:
35159f4ada15SMatthew G. Knepley + dm   - The DMPlex
351620f4b53cSBarry Smith . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
35179f4ada15SMatthew G. Knepley . cone - An array of points which are on the in-edges for point p
351820f4b53cSBarry Smith - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
35199f4ada15SMatthew G. Knepley         integer giving the prescription for cone traversal.
35209f4ada15SMatthew G. Knepley 
35219f4ada15SMatthew G. Knepley   Level: beginner
35229f4ada15SMatthew G. Knepley 
35239f4ada15SMatthew G. Knepley   Notes:
35249f4ada15SMatthew G. Knepley   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
35259f4ada15SMatthew G. Knepley   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
352620f4b53cSBarry Smith   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
35279f4ada15SMatthew G. Knepley   with the identity.
35289f4ada15SMatthew G. Knepley 
352960225df5SJacob Faibussowitsch   Fortran Notes:
353020f4b53cSBarry Smith   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
353120f4b53cSBarry Smith   `DMPlexRestoreCone()` is not needed/available in C.
35329f4ada15SMatthew G. Knepley 
35331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
35349f4ada15SMatthew G. Knepley @*/
35359f4ada15SMatthew G. Knepley PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
35369f4ada15SMatthew G. Knepley {
35379f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
35389f4ada15SMatthew G. Knepley 
35399f4ada15SMatthew G. Knepley   PetscFunctionBegin;
35409f4ada15SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35419f4ada15SMatthew G. Knepley   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
35423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35439f4ada15SMatthew G. Knepley }
35449f4ada15SMatthew G. Knepley 
3545552f7358SJed Brown /*@
3546eaf898f9SPatrick Sanan   DMPlexGetSupportSize - Return 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()`
3553552f7358SJed Brown 
3554552f7358SJed Brown   Output Parameter:
355520f4b53cSBarry Smith . size - The support size for point `p`
3556552f7358SJed Brown 
3557552f7358SJed Brown   Level: beginner
3558552f7358SJed Brown 
35591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3560552f7358SJed Brown @*/
3561d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3562d71ae5a4SJacob Faibussowitsch {
3563552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3564552f7358SJed Brown 
3565552f7358SJed Brown   PetscFunctionBegin;
3566552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35674f572ea9SToby Isaac   PetscAssertPointer(size, 3);
35689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
35693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3570552f7358SJed Brown }
3571552f7358SJed Brown 
3572552f7358SJed Brown /*@
3573eaf898f9SPatrick Sanan   DMPlexSetSupportSize - Set the number of 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()`
358020f4b53cSBarry Smith - size - The support size for point `p`
3581552f7358SJed Brown 
3582a1cb98faSBarry Smith   Level: beginner
3583552f7358SJed Brown 
3584552f7358SJed Brown   Note:
358520f4b53cSBarry Smith   This should be called after `DMPlexSetChart()`.
3586552f7358SJed Brown 
35871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3588552f7358SJed Brown @*/
3589d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3590d71ae5a4SJacob Faibussowitsch {
3591552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3592552f7358SJed Brown 
3593552f7358SJed Brown   PetscFunctionBegin;
3594552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35959566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
35963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3597552f7358SJed Brown }
3598552f7358SJed Brown 
3599552f7358SJed Brown /*@C
3600eaf898f9SPatrick Sanan   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3601552f7358SJed Brown 
3602a1cb98faSBarry Smith   Not Collective
3603552f7358SJed Brown 
3604552f7358SJed Brown   Input Parameters:
360560225df5SJacob Faibussowitsch + dm - The `DMPLEX`
3606a1cb98faSBarry Smith - p  - The point, which must lie in the chart set with `DMPlexSetChart()`
3607552f7358SJed Brown 
3608552f7358SJed Brown   Output Parameter:
360920f4b53cSBarry Smith . support - An array of points which are on the out-edges for point `p`
3610552f7358SJed Brown 
3611552f7358SJed Brown   Level: beginner
3612552f7358SJed Brown 
361360225df5SJacob Faibussowitsch   Fortran Notes:
3614a1cb98faSBarry Smith   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3615a1cb98faSBarry Smith   `DMPlexRestoreSupport()` is not needed/available in C.
36163813dfbdSMatthew G Knepley 
36171cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3618552f7358SJed Brown @*/
3619d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3620d71ae5a4SJacob Faibussowitsch {
3621552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3622552f7358SJed Brown   PetscInt off;
3623552f7358SJed Brown 
3624552f7358SJed Brown   PetscFunctionBegin;
3625552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36264f572ea9SToby Isaac   PetscAssertPointer(support, 3);
36279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
36288e3a54c0SPierre Jolivet   *support = PetscSafePointerPlusOffset(mesh->supports, off);
36293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3630552f7358SJed Brown }
3631552f7358SJed Brown 
3632552f7358SJed Brown /*@
363392371b87SBarry 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
3634552f7358SJed Brown 
3635a1cb98faSBarry Smith   Not Collective
3636552f7358SJed Brown 
3637552f7358SJed Brown   Input Parameters:
363860225df5SJacob Faibussowitsch + dm      - The `DMPLEX`
3639a1cb98faSBarry Smith . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
364020f4b53cSBarry Smith - support - An array of points which are on the out-edges for point `p`
3641552f7358SJed Brown 
3642552f7358SJed Brown   Level: beginner
3643552f7358SJed Brown 
3644a1cb98faSBarry Smith   Note:
3645a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3646a1cb98faSBarry Smith 
36471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3648552f7358SJed Brown @*/
3649d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3650d71ae5a4SJacob Faibussowitsch {
3651552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3652552f7358SJed Brown   PetscInt pStart, pEnd;
3653552f7358SJed Brown   PetscInt dof, off, c;
3654552f7358SJed Brown 
3655552f7358SJed Brown   PetscFunctionBegin;
3656552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
36589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
36594f572ea9SToby Isaac   if (dof) PetscAssertPointer(support, 3);
36609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
366163a3b9bcSJacob 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);
3662552f7358SJed Brown   for (c = 0; c < dof; ++c) {
366363a3b9bcSJacob 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);
3664552f7358SJed Brown     mesh->supports[off + c] = support[c];
3665552f7358SJed Brown   }
36663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3667552f7358SJed Brown }
3668552f7358SJed Brown 
36697cd05799SMatthew G. Knepley /*@
3670eaf898f9SPatrick Sanan   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
36717cd05799SMatthew G. Knepley 
3672a1cb98faSBarry Smith   Not Collective
36737cd05799SMatthew G. Knepley 
36747cd05799SMatthew G. Knepley   Input Parameters:
367560225df5SJacob Faibussowitsch + dm           - The `DMPLEX`
3676a1cb98faSBarry Smith . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
36777cd05799SMatthew G. Knepley . supportPos   - The local index in the cone where the point should be put
36787cd05799SMatthew G. Knepley - supportPoint - The mesh point to insert
36797cd05799SMatthew G. Knepley 
36807cd05799SMatthew G. Knepley   Level: beginner
36817cd05799SMatthew G. Knepley 
36821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
36837cd05799SMatthew G. Knepley @*/
3684d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3685d71ae5a4SJacob Faibussowitsch {
3686552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
3687552f7358SJed Brown   PetscInt pStart, pEnd;
3688552f7358SJed Brown   PetscInt dof, off;
3689552f7358SJed Brown 
3690552f7358SJed Brown   PetscFunctionBegin;
3691552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
36929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
36939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
36949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
369563a3b9bcSJacob 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);
369663a3b9bcSJacob 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);
369763a3b9bcSJacob 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);
3698552f7358SJed Brown   mesh->supports[off + supportPos] = supportPoint;
36993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3700552f7358SJed Brown }
3701552f7358SJed Brown 
3702b5a892a1SMatthew G. Knepley /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3703d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3704d71ae5a4SJacob Faibussowitsch {
3705b5a892a1SMatthew G. Knepley   switch (ct) {
3706b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3707b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3708b5a892a1SMatthew G. Knepley     break;
3709b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3710b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3711b5a892a1SMatthew G. Knepley     if (o == -2) return -3;
3712b5a892a1SMatthew G. Knepley     if (o == -1) return -2;
3713b5a892a1SMatthew G. Knepley     break;
3714b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3715b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3716b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3717b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3718b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3719b5a892a1SMatthew G. Knepley     break;
3720d71ae5a4SJacob Faibussowitsch   default:
3721d71ae5a4SJacob Faibussowitsch     return o;
3722b5a892a1SMatthew G. Knepley   }
3723b5a892a1SMatthew G. Knepley   return o;
3724b5a892a1SMatthew G. Knepley }
3725b5a892a1SMatthew G. Knepley 
3726b5a892a1SMatthew G. Knepley /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3727d71ae5a4SJacob Faibussowitsch PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3728d71ae5a4SJacob Faibussowitsch {
3729b5a892a1SMatthew G. Knepley   switch (ct) {
3730b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
3731b5a892a1SMatthew G. Knepley     if ((o == -2) || (o == 1)) return -1;
3732b5a892a1SMatthew G. Knepley     if (o == -1) return 0;
3733b5a892a1SMatthew G. Knepley     break;
3734b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
3735b5a892a1SMatthew G. Knepley     if (o == -3) return -2;
3736b5a892a1SMatthew G. Knepley     if (o == -2) return -1;
3737b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3738b5a892a1SMatthew G. Knepley     break;
3739b5a892a1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
3740b5a892a1SMatthew G. Knepley     if (o == -4) return -2;
3741b5a892a1SMatthew G. Knepley     if (o == -3) return -1;
3742b5a892a1SMatthew G. Knepley     if (o == -2) return -4;
3743b5a892a1SMatthew G. Knepley     if (o == -1) return -3;
3744b5a892a1SMatthew G. Knepley     break;
3745d71ae5a4SJacob Faibussowitsch   default:
3746d71ae5a4SJacob Faibussowitsch     return o;
3747b5a892a1SMatthew G. Knepley   }
3748b5a892a1SMatthew G. Knepley   return o;
3749b5a892a1SMatthew G. Knepley }
3750b5a892a1SMatthew G. Knepley 
3751b5a892a1SMatthew G. Knepley /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3752d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3753d71ae5a4SJacob Faibussowitsch {
3754b5a892a1SMatthew G. Knepley   PetscInt pStart, pEnd, p;
3755b5a892a1SMatthew G. Knepley 
3756b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
37579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3758b5a892a1SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
3759b5a892a1SMatthew G. Knepley     const PetscInt *cone, *ornt;
3760b5a892a1SMatthew G. Knepley     PetscInt        coneSize, c;
3761b5a892a1SMatthew G. Knepley 
37629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
37639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
37649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3765b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
3766b5a892a1SMatthew G. Knepley       DMPolytopeType ct;
3767b5a892a1SMatthew G. Knepley       const PetscInt o = ornt[c];
3768b5a892a1SMatthew G. Knepley 
37699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3770b5a892a1SMatthew G. Knepley       switch (ct) {
3771b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_SEGMENT:
37729566063dSJacob Faibussowitsch         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
37739566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3774b5a892a1SMatthew G. Knepley         break;
3775b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_TRIANGLE:
37769566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
37779566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
37789566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3779b5a892a1SMatthew G. Knepley         break;
3780b5a892a1SMatthew G. Knepley       case DM_POLYTOPE_QUADRILATERAL:
37819566063dSJacob Faibussowitsch         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
37829566063dSJacob Faibussowitsch         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
37839566063dSJacob Faibussowitsch         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
37849566063dSJacob Faibussowitsch         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3785b5a892a1SMatthew G. Knepley         break;
3786d71ae5a4SJacob Faibussowitsch       default:
3787d71ae5a4SJacob Faibussowitsch         break;
3788b5a892a1SMatthew G. Knepley       }
3789b5a892a1SMatthew G. Knepley     }
3790b5a892a1SMatthew G. Knepley   }
37913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3792b5a892a1SMatthew G. Knepley }
3793b5a892a1SMatthew G. Knepley 
379409015e70SStefano Zampini static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
379509015e70SStefano Zampini {
379609015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
379709015e70SStefano Zampini 
379809015e70SStefano Zampini   PetscFunctionBeginHot;
379909015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
380009015e70SStefano Zampini     if (useCone) {
380109015e70SStefano Zampini       PetscCall(DMPlexGetConeSize(dm, p, size));
380209015e70SStefano Zampini       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
380309015e70SStefano Zampini     } else {
380409015e70SStefano Zampini       PetscCall(DMPlexGetSupportSize(dm, p, size));
380509015e70SStefano Zampini       PetscCall(DMPlexGetSupport(dm, p, arr));
380609015e70SStefano Zampini     }
380709015e70SStefano Zampini   } else {
380809015e70SStefano Zampini     if (useCone) {
380909015e70SStefano Zampini       const PetscSection s   = mesh->coneSection;
381009015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
381109015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
381209015e70SStefano Zampini 
381309015e70SStefano Zampini       *size = s->atlasDof[ps];
381409015e70SStefano Zampini       *arr  = mesh->cones + off;
381509015e70SStefano Zampini       *ornt = mesh->coneOrientations + off;
381609015e70SStefano Zampini     } else {
381709015e70SStefano Zampini       const PetscSection s   = mesh->supportSection;
381809015e70SStefano Zampini       const PetscInt     ps  = p - s->pStart;
381909015e70SStefano Zampini       const PetscInt     off = s->atlasOff[ps];
382009015e70SStefano Zampini 
382109015e70SStefano Zampini       *size = s->atlasDof[ps];
382209015e70SStefano Zampini       *arr  = mesh->supports + off;
382309015e70SStefano Zampini     }
382409015e70SStefano Zampini   }
382509015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
382609015e70SStefano Zampini }
382709015e70SStefano Zampini 
382809015e70SStefano Zampini static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
382909015e70SStefano Zampini {
383009015e70SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
383109015e70SStefano Zampini 
383209015e70SStefano Zampini   PetscFunctionBeginHot;
383309015e70SStefano Zampini   if (PetscDefined(USE_DEBUG) || mesh->tr) {
383409015e70SStefano Zampini     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
383509015e70SStefano Zampini   }
383609015e70SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
383709015e70SStefano Zampini }
383809015e70SStefano Zampini 
3839d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3840d71ae5a4SJacob Faibussowitsch {
3841b5a892a1SMatthew G. Knepley   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3842b5a892a1SMatthew G. Knepley   PetscInt       *closure;
3843b5a892a1SMatthew G. Knepley   const PetscInt *tmp = NULL, *tmpO = NULL;
3844b5a892a1SMatthew G. Knepley   PetscInt        off = 0, tmpSize, t;
3845b5a892a1SMatthew G. Knepley 
3846b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
3847b5a892a1SMatthew G. Knepley   if (ornt) {
38489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, p, &ct));
3849476787b7SMatthew 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;
3850b5a892a1SMatthew G. Knepley   }
3851b5a892a1SMatthew G. Knepley   if (*points) {
3852b5a892a1SMatthew G. Knepley     closure = *points;
3853b5a892a1SMatthew G. Knepley   } else {
3854b5a892a1SMatthew G. Knepley     PetscInt maxConeSize, maxSupportSize;
38559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
38569566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3857b5a892a1SMatthew G. Knepley   }
385809015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3859b5a892a1SMatthew G. Knepley   if (ct == DM_POLYTOPE_UNKNOWN) {
3860b5a892a1SMatthew G. Knepley     closure[off++] = p;
3861b5a892a1SMatthew G. Knepley     closure[off++] = 0;
3862b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3863b5a892a1SMatthew G. Knepley       closure[off++] = tmp[t];
3864b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? tmpO[t] : 0;
3865b5a892a1SMatthew G. Knepley     }
3866b5a892a1SMatthew G. Knepley   } else {
386785036b15SMatthew G. Knepley     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt);
3868b5a892a1SMatthew G. Knepley 
3869b5a892a1SMatthew G. Knepley     /* We assume that cells with a valid type have faces with a valid type */
3870b5a892a1SMatthew G. Knepley     closure[off++] = p;
3871b5a892a1SMatthew G. Knepley     closure[off++] = ornt;
3872b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
3873b5a892a1SMatthew G. Knepley       DMPolytopeType ft;
3874b5a892a1SMatthew G. Knepley 
38759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3876b5a892a1SMatthew G. Knepley       closure[off++] = tmp[arr[t]];
3877b5a892a1SMatthew G. Knepley       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3878b5a892a1SMatthew G. Knepley     }
3879b5a892a1SMatthew G. Knepley   }
388009015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3881b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = tmpSize + 1;
3882b5a892a1SMatthew G. Knepley   if (points) *points = closure;
38833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3884b5a892a1SMatthew G. Knepley }
3885b5a892a1SMatthew G. Knepley 
3886d5b43468SJose E. Roman /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3887d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3888d71ae5a4SJacob Faibussowitsch {
388985036b15SMatthew G. Knepley   const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
3890b5a892a1SMatthew G. Knepley   const PetscInt *cone, *ornt;
3891b5a892a1SMatthew G. Knepley   PetscInt       *pts, *closure = NULL;
3892b5a892a1SMatthew G. Knepley   DMPolytopeType  ft;
3893b5a892a1SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3894b5a892a1SMatthew G. Knepley   PetscInt        dim, coneSize, c, d, clSize, cl;
3895b5a892a1SMatthew G. Knepley 
3896b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
38979566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
389809015e70SStefano Zampini   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
38999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3900b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3901b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3902b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
39039371c9d4SSatish Balay   if (*points) {
39049371c9d4SSatish Balay     pts = *points;
39059371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3906b5a892a1SMatthew G. Knepley   c        = 0;
3907b5a892a1SMatthew G. Knepley   pts[c++] = point;
3908b5a892a1SMatthew G. Knepley   pts[c++] = o;
39099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
39109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
39119371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
39129371c9d4SSatish Balay     pts[c++] = closure[cl];
39139371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
39149371c9d4SSatish Balay   }
39159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
39169371c9d4SSatish Balay   for (cl = 0; cl < clSize * 2; cl += 2) {
39179371c9d4SSatish Balay     pts[c++] = closure[cl];
39189371c9d4SSatish Balay     pts[c++] = closure[cl + 1];
39199371c9d4SSatish Balay   }
39209566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3921b5a892a1SMatthew G. Knepley   for (d = 2; d < coneSize; ++d) {
39229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3923b5a892a1SMatthew G. Knepley     pts[c++] = cone[arr[d * 2 + 0]];
3924b5a892a1SMatthew G. Knepley     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3925b5a892a1SMatthew G. Knepley   }
392609015e70SStefano Zampini   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3927b5a892a1SMatthew G. Knepley   if (dim >= 3) {
3928b5a892a1SMatthew G. Knepley     for (d = 2; d < coneSize; ++d) {
3929b5a892a1SMatthew G. Knepley       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3930b5a892a1SMatthew G. Knepley       const PetscInt *fcone, *fornt;
3931b5a892a1SMatthew G. Knepley       PetscInt        fconeSize, fc, i;
3932b5a892a1SMatthew G. Knepley 
39339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
393485036b15SMatthew G. Knepley       const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
393509015e70SStefano Zampini       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3936b5a892a1SMatthew G. Knepley       for (fc = 0; fc < fconeSize; ++fc) {
3937b5a892a1SMatthew G. Knepley         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3938b5a892a1SMatthew G. Knepley         const PetscInt co = farr[fc * 2 + 1];
3939b5a892a1SMatthew G. Knepley 
39409371c9d4SSatish Balay         for (i = 0; i < c; i += 2)
39419371c9d4SSatish Balay           if (pts[i] == cp) break;
3942b5a892a1SMatthew G. Knepley         if (i == c) {
39439566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3944b5a892a1SMatthew G. Knepley           pts[c++] = cp;
3945b5a892a1SMatthew G. Knepley           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3946b5a892a1SMatthew G. Knepley         }
3947b5a892a1SMatthew G. Knepley       }
394809015e70SStefano Zampini       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3949b5a892a1SMatthew G. Knepley     }
3950b5a892a1SMatthew G. Knepley   }
3951b5a892a1SMatthew G. Knepley   *numPoints = c / 2;
3952b5a892a1SMatthew G. Knepley   *points    = pts;
39533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3954b5a892a1SMatthew G. Knepley }
3955b5a892a1SMatthew G. Knepley 
3956d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3957d71ae5a4SJacob Faibussowitsch {
3958b5a892a1SMatthew G. Knepley   DMPolytopeType ct;
3959b5a892a1SMatthew G. Knepley   PetscInt      *closure, *fifo;
3960b5a892a1SMatthew G. Knepley   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3961b5a892a1SMatthew G. Knepley   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3962b5a892a1SMatthew G. Knepley   PetscInt       depth, maxSize;
3963b5a892a1SMatthew G. Knepley 
3964b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
39659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
3966b5a892a1SMatthew G. Knepley   if (depth == 1) {
39679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
39683ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3969b5a892a1SMatthew G. Knepley   }
39709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
3971476787b7SMatthew 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;
3972c306944fSJed Brown   if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) {
39739566063dSJacob Faibussowitsch     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
39743ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
3975b5a892a1SMatthew G. Knepley   }
39769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3977b5a892a1SMatthew G. Knepley   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3978b5a892a1SMatthew G. Knepley   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3979b5a892a1SMatthew G. Knepley   maxSize       = PetscMax(coneSeries, supportSeries);
39809566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
39819371c9d4SSatish Balay   if (*points) {
39829371c9d4SSatish Balay     closure = *points;
39839371c9d4SSatish Balay   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
3984b5a892a1SMatthew G. Knepley   closure[closureSize++] = p;
3985b5a892a1SMatthew G. Knepley   closure[closureSize++] = ornt;
3986b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = p;
3987b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ornt;
3988b5a892a1SMatthew G. Knepley   fifo[fifoSize++]       = ct;
3989b5a892a1SMatthew G. Knepley   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3990b5a892a1SMatthew G. Knepley   while (fifoSize - fifoStart) {
3991b5a892a1SMatthew G. Knepley     const PetscInt       q    = fifo[fifoStart++];
3992b5a892a1SMatthew G. Knepley     const PetscInt       o    = fifo[fifoStart++];
3993b5a892a1SMatthew G. Knepley     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
399485036b15SMatthew G. Knepley     const PetscInt      *qarr = DMPolytopeTypeGetArrangement(qt, o);
399509015e70SStefano Zampini     const PetscInt      *tmp, *tmpO = NULL;
3996b5a892a1SMatthew G. Knepley     PetscInt             tmpSize, t;
3997b5a892a1SMatthew G. Knepley 
3998b5a892a1SMatthew G. Knepley     if (PetscDefined(USE_DEBUG)) {
399985036b15SMatthew G. Knepley       PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2;
400063a3b9bcSJacob 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);
4001b5a892a1SMatthew G. Knepley     }
400209015e70SStefano Zampini     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4003b5a892a1SMatthew G. Knepley     for (t = 0; t < tmpSize; ++t) {
4004b5a892a1SMatthew G. Knepley       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
4005b5a892a1SMatthew G. Knepley       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
4006b5a892a1SMatthew G. Knepley       const PetscInt cp = tmp[ip];
40079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cp, &ct));
4008b5a892a1SMatthew G. Knepley       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
4009b5a892a1SMatthew G. Knepley       PetscInt       c;
4010b5a892a1SMatthew G. Knepley 
4011b5a892a1SMatthew G. Knepley       /* Check for duplicate */
4012b5a892a1SMatthew G. Knepley       for (c = 0; c < closureSize; c += 2) {
4013b5a892a1SMatthew G. Knepley         if (closure[c] == cp) break;
4014b5a892a1SMatthew G. Knepley       }
4015b5a892a1SMatthew G. Knepley       if (c == closureSize) {
4016b5a892a1SMatthew G. Knepley         closure[closureSize++] = cp;
4017b5a892a1SMatthew G. Knepley         closure[closureSize++] = co;
4018b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = cp;
4019b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = co;
4020b5a892a1SMatthew G. Knepley         fifo[fifoSize++]       = ct;
4021b5a892a1SMatthew G. Knepley       }
4022b5a892a1SMatthew G. Knepley     }
402309015e70SStefano Zampini     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
4024b5a892a1SMatthew G. Knepley   }
40259566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
4026b5a892a1SMatthew G. Knepley   if (numPoints) *numPoints = closureSize / 2;
4027b5a892a1SMatthew G. Knepley   if (points) *points = closure;
40283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4029b5a892a1SMatthew G. Knepley }
4030b5a892a1SMatthew G. Knepley 
4031552f7358SJed Brown /*@C
4032eaf898f9SPatrick Sanan   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
4033552f7358SJed Brown 
4034a1cb98faSBarry Smith   Not Collective
4035552f7358SJed Brown 
4036552f7358SJed Brown   Input Parameters:
4037a1cb98faSBarry Smith + dm      - The `DMPLEX`
4038b5a892a1SMatthew G. Knepley . p       - The mesh point
4039a1cb98faSBarry Smith - useCone - `PETSC_TRUE` for the closure, otherwise return the star
4040552f7358SJed Brown 
40416b867d5aSJose E. Roman   Input/Output Parameter:
40426b867d5aSJose E. Roman . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
404320f4b53cSBarry Smith            if `NULL` on input, internal storage will be returned, otherwise the provided array is used
40446b867d5aSJose E. Roman 
40456b867d5aSJose E. Roman   Output Parameter:
404620f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4047552f7358SJed Brown 
4048a1cb98faSBarry Smith   Level: beginner
4049a1cb98faSBarry Smith 
4050552f7358SJed Brown   Note:
405120f4b53cSBarry Smith   If using internal storage (points is `NULL` on input), each call overwrites the last output.
4052552f7358SJed Brown 
405360225df5SJacob Faibussowitsch   Fortran Notes:
405420f4b53cSBarry Smith   The `numPoints` argument is not present in the Fortran binding since it is internal to the array.
40553813dfbdSMatthew G Knepley 
40561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4057552f7358SJed Brown @*/
4058d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4059d71ae5a4SJacob Faibussowitsch {
4060b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4061552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40624f572ea9SToby Isaac   if (numPoints) PetscAssertPointer(numPoints, 4);
40634f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 5);
40649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
40653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40669bf0dad6SMatthew G. Knepley }
40679bf0dad6SMatthew G. Knepley 
4068552f7358SJed Brown /*@C
4069eaf898f9SPatrick Sanan   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
4070552f7358SJed Brown 
4071a1cb98faSBarry Smith   Not Collective
4072552f7358SJed Brown 
4073552f7358SJed Brown   Input Parameters:
4074a1cb98faSBarry Smith + dm        - The `DMPLEX`
4075b5a892a1SMatthew G. Knepley . p         - The mesh point
4076a1cb98faSBarry Smith . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
407720f4b53cSBarry Smith . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
4078b5a892a1SMatthew G. Knepley - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
4079552f7358SJed Brown 
4080a1cb98faSBarry Smith   Level: beginner
4081a1cb98faSBarry Smith 
4082552f7358SJed Brown   Note:
408320f4b53cSBarry Smith   If not using internal storage (points is not `NULL` on input), this call is unnecessary
4084552f7358SJed Brown 
40851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
4086552f7358SJed Brown @*/
4087d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
4088d71ae5a4SJacob Faibussowitsch {
4089b5a892a1SMatthew G. Knepley   PetscFunctionBeginHot;
4090552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40914ff43b2cSJed Brown   if (numPoints) *numPoints = 0;
40929566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
40933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4094552f7358SJed Brown }
4095552f7358SJed Brown 
4096552f7358SJed Brown /*@
4097eaf898f9SPatrick Sanan   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
4098552f7358SJed Brown 
4099a1cb98faSBarry Smith   Not Collective
4100552f7358SJed Brown 
4101552f7358SJed Brown   Input Parameter:
410260225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4103552f7358SJed Brown 
4104552f7358SJed Brown   Output Parameters:
4105552f7358SJed Brown + maxConeSize    - The maximum number of in-edges
4106552f7358SJed Brown - maxSupportSize - The maximum number of out-edges
4107552f7358SJed Brown 
4108552f7358SJed Brown   Level: beginner
4109552f7358SJed Brown 
41101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
4111552f7358SJed Brown @*/
4112d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
4113d71ae5a4SJacob Faibussowitsch {
4114552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
4115552f7358SJed Brown 
4116552f7358SJed Brown   PetscFunctionBegin;
4117552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41181baa6e33SBarry Smith   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
41191baa6e33SBarry Smith   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
41203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4121552f7358SJed Brown }
4122552f7358SJed Brown 
4123d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetUp_Plex(DM dm)
4124d71ae5a4SJacob Faibussowitsch {
4125552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
41266302a7fbSVaclav Hapla   PetscInt size, maxSupportSize;
4127552f7358SJed Brown 
4128552f7358SJed Brown   PetscFunctionBegin;
4129552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->coneSection));
41319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
41329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &mesh->cones));
41339566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
41346302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
41356302a7fbSVaclav Hapla   if (maxSupportSize) {
41369566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(mesh->supportSection));
41379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
41389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->supports));
4139552f7358SJed Brown   }
41403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4141552f7358SJed Brown }
4142552f7358SJed Brown 
4143d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
4144d71ae5a4SJacob Faibussowitsch {
4145552f7358SJed Brown   PetscFunctionBegin;
41469566063dSJacob Faibussowitsch   if (subdm) PetscCall(DMClone(dm, subdm));
41479566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
4148ad540459SPierre Jolivet   if (subdm) (*subdm)->useNatural = dm->useNatural;
4149736995cdSBlaise Bourdin   if (dm->useNatural && dm->sfMigration) {
415095602cf2SAlexis Marboeuf     PetscSF sfNatural;
4151f94b4a02SBlaise Bourdin 
41523dcd263cSBlaise Bourdin     (*subdm)->sfMigration = dm->sfMigration;
41539566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
415495602cf2SAlexis Marboeuf     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
4155c40e9495SBlaise Bourdin     (*subdm)->sfNatural = sfNatural;
4156f94b4a02SBlaise Bourdin   }
41573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4158552f7358SJed Brown }
4159552f7358SJed Brown 
4160d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
4161d71ae5a4SJacob Faibussowitsch {
41623dcd263cSBlaise Bourdin   PetscInt i = 0;
41632adcc780SMatthew G. Knepley 
41642adcc780SMatthew G. Knepley   PetscFunctionBegin;
41659566063dSJacob Faibussowitsch   PetscCall(DMClone(dms[0], superdm));
41669566063dSJacob Faibussowitsch   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
4167c40e9495SBlaise Bourdin   (*superdm)->useNatural = PETSC_FALSE;
41683dcd263cSBlaise Bourdin   for (i = 0; i < len; i++) {
41693dcd263cSBlaise Bourdin     if (dms[i]->useNatural && dms[i]->sfMigration) {
417095602cf2SAlexis Marboeuf       PetscSF sfNatural;
41713dcd263cSBlaise Bourdin 
41723dcd263cSBlaise Bourdin       (*superdm)->sfMigration = dms[i]->sfMigration;
41739566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4174c40e9495SBlaise Bourdin       (*superdm)->useNatural = PETSC_TRUE;
417595602cf2SAlexis Marboeuf       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4176c40e9495SBlaise Bourdin       (*superdm)->sfNatural = sfNatural;
41773dcd263cSBlaise Bourdin       break;
41783dcd263cSBlaise Bourdin     }
41793dcd263cSBlaise Bourdin   }
41803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41812adcc780SMatthew G. Knepley }
41822adcc780SMatthew G. Knepley 
4183552f7358SJed Brown /*@
4184eaf898f9SPatrick Sanan   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4185552f7358SJed Brown 
4186a1cb98faSBarry Smith   Not Collective
4187552f7358SJed Brown 
4188552f7358SJed Brown   Input Parameter:
418960225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4190552f7358SJed Brown 
4191552f7358SJed Brown   Level: beginner
4192552f7358SJed Brown 
4193a1cb98faSBarry Smith   Note:
4194a1cb98faSBarry Smith   This should be called after all calls to `DMPlexSetCone()`
4195a1cb98faSBarry Smith 
41961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4197552f7358SJed Brown @*/
4198d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSymmetrize(DM dm)
4199d71ae5a4SJacob Faibussowitsch {
4200552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4201552f7358SJed Brown   PetscInt *offsets;
4202552f7358SJed Brown   PetscInt  supportSize;
4203552f7358SJed Brown   PetscInt  pStart, pEnd, p;
4204552f7358SJed Brown 
4205552f7358SJed Brown   PetscFunctionBegin;
4206552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
420728b400f6SJacob Faibussowitsch   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
42089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4209552f7358SJed Brown   /* Calculate support sizes */
42109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4211552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4212552f7358SJed Brown     PetscInt dof, off, c;
4213552f7358SJed Brown 
42149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
42159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
421648a46eb9SPierre Jolivet     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4217552f7358SJed Brown   }
42189566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(mesh->supportSection));
4219552f7358SJed Brown   /* Calculate supports */
42209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
42219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
42229566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4223552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
4224552f7358SJed Brown     PetscInt dof, off, c;
4225552f7358SJed Brown 
42269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
42279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4228552f7358SJed Brown     for (c = off; c < off + dof; ++c) {
4229552f7358SJed Brown       const PetscInt q = mesh->cones[c];
4230552f7358SJed Brown       PetscInt       offS;
4231552f7358SJed Brown 
42329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
42330d644c17SKarl Rupp 
4234552f7358SJed Brown       mesh->supports[offS + offsets[q]] = p;
4235552f7358SJed Brown       ++offsets[q];
4236552f7358SJed Brown     }
4237552f7358SJed Brown   }
42389566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
42399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
42403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4241552f7358SJed Brown }
4242552f7358SJed Brown 
4243d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4244d71ae5a4SJacob Faibussowitsch {
4245277ea44aSLisandro Dalcin   IS stratumIS;
4246277ea44aSLisandro Dalcin 
4247277ea44aSLisandro Dalcin   PetscFunctionBegin;
42483ba16761SJacob Faibussowitsch   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
424976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
4250277ea44aSLisandro Dalcin     PetscInt  qStart, qEnd, numLevels, level;
4251277ea44aSLisandro Dalcin     PetscBool overlap = PETSC_FALSE;
42529566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numLevels));
4253277ea44aSLisandro Dalcin     for (level = 0; level < numLevels; level++) {
42549566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
42559371c9d4SSatish Balay       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
42569371c9d4SSatish Balay         overlap = PETSC_TRUE;
42579371c9d4SSatish Balay         break;
42589371c9d4SSatish Balay       }
4259277ea44aSLisandro Dalcin     }
426063a3b9bcSJacob 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);
4261277ea44aSLisandro Dalcin   }
42629566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
42639566063dSJacob Faibussowitsch   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
42649566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&stratumIS));
42653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4266277ea44aSLisandro Dalcin }
4267277ea44aSLisandro Dalcin 
4268e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label)
4269e91fa0a1SMatthew G. Knepley {
4270e91fa0a1SMatthew G. Knepley   PetscInt *pMin, *pMax;
4271e91fa0a1SMatthew G. Knepley   PetscInt  pStart, pEnd;
4272e91fa0a1SMatthew G. Knepley   PetscInt  dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT;
4273e91fa0a1SMatthew G. Knepley 
4274e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4275e91fa0a1SMatthew G. Knepley   {
4276e91fa0a1SMatthew G. Knepley     DMLabel label2;
4277e91fa0a1SMatthew G. Knepley 
4278e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellTypeLabel(dm, &label2));
4279e91fa0a1SMatthew G. Knepley     PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view"));
4280e91fa0a1SMatthew G. Knepley   }
4281e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4282e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4283e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4284e91fa0a1SMatthew G. Knepley 
4285e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4286e91fa0a1SMatthew G. Knepley     dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin);
4287e91fa0a1SMatthew G. Knepley     dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax);
4288e91fa0a1SMatthew G. Knepley   }
4289e91fa0a1SMatthew G. Knepley   PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax));
4290e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4291e91fa0a1SMatthew G. Knepley     pMin[d] = PETSC_MAX_INT;
4292e91fa0a1SMatthew G. Knepley     pMax[d] = PETSC_MIN_INT;
4293e91fa0a1SMatthew G. Knepley   }
4294e91fa0a1SMatthew G. Knepley   for (PetscInt p = pStart; p < pEnd; ++p) {
4295e91fa0a1SMatthew G. Knepley     DMPolytopeType ct;
4296e91fa0a1SMatthew G. Knepley     PetscInt       d;
4297e91fa0a1SMatthew G. Knepley 
4298e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexGetCellType(dm, p, &ct));
4299e91fa0a1SMatthew G. Knepley     d       = DMPolytopeTypeGetDim(ct);
4300e91fa0a1SMatthew G. Knepley     pMin[d] = PetscMin(p, pMin[d]);
4301e91fa0a1SMatthew G. Knepley     pMax[d] = PetscMax(p, pMax[d]);
4302e91fa0a1SMatthew G. Knepley   }
4303e91fa0a1SMatthew G. Knepley   for (PetscInt d = dmin; d <= dmax; ++d) {
4304e91fa0a1SMatthew G. Knepley     if (pMin[d] > pMax[d]) continue;
4305e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1));
4306e91fa0a1SMatthew G. Knepley   }
4307e91fa0a1SMatthew G. Knepley   PetscCall(PetscFree2(pMin, pMax));
4308e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4309e91fa0a1SMatthew G. Knepley }
4310e91fa0a1SMatthew G. Knepley 
4311e91fa0a1SMatthew G. Knepley static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label)
4312e91fa0a1SMatthew G. Knepley {
4313e91fa0a1SMatthew G. Knepley   PetscInt pStart, pEnd;
4314e91fa0a1SMatthew G. Knepley   PetscInt numRoots = 0, numLeaves = 0;
4315e91fa0a1SMatthew G. Knepley 
4316e91fa0a1SMatthew G. Knepley   PetscFunctionBegin;
4317e91fa0a1SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4318e91fa0a1SMatthew G. Knepley   {
4319e91fa0a1SMatthew G. Knepley     /* Initialize roots and count leaves */
4320e91fa0a1SMatthew G. Knepley     PetscInt sMin = PETSC_MAX_INT;
4321e91fa0a1SMatthew G. Knepley     PetscInt sMax = PETSC_MIN_INT;
4322e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4323e91fa0a1SMatthew G. Knepley 
4324e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4325e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4326e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4327e91fa0a1SMatthew G. Knepley       if (!coneSize && supportSize) {
4328e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4329e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4330e91fa0a1SMatthew G. Knepley         ++numRoots;
4331e91fa0a1SMatthew G. Knepley       } else if (!supportSize && coneSize) {
4332e91fa0a1SMatthew G. Knepley         ++numLeaves;
4333e91fa0a1SMatthew G. Knepley       } else if (!supportSize && !coneSize) {
4334e91fa0a1SMatthew G. Knepley         /* Isolated points */
4335e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4336e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4337e91fa0a1SMatthew G. Knepley       }
4338e91fa0a1SMatthew G. Knepley     }
4339e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4340e91fa0a1SMatthew G. Knepley   }
4341e91fa0a1SMatthew G. Knepley 
4342e91fa0a1SMatthew G. Knepley   if (numRoots + numLeaves == (pEnd - pStart)) {
4343e91fa0a1SMatthew G. Knepley     PetscInt sMin = PETSC_MAX_INT;
4344e91fa0a1SMatthew G. Knepley     PetscInt sMax = PETSC_MIN_INT;
4345e91fa0a1SMatthew G. Knepley     PetscInt coneSize, supportSize;
4346e91fa0a1SMatthew G. Knepley 
4347e91fa0a1SMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; ++p) {
4348e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4349e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4350e91fa0a1SMatthew G. Knepley       if (!supportSize && coneSize) {
4351e91fa0a1SMatthew G. Knepley         sMin = PetscMin(p, sMin);
4352e91fa0a1SMatthew G. Knepley         sMax = PetscMax(p, sMax);
4353e91fa0a1SMatthew G. Knepley       }
4354e91fa0a1SMatthew G. Knepley     }
4355e91fa0a1SMatthew G. Knepley     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4356e91fa0a1SMatthew G. Knepley   } else {
4357e91fa0a1SMatthew G. Knepley     PetscInt level = 0;
4358e91fa0a1SMatthew G. Knepley     PetscInt qStart, qEnd;
4359e91fa0a1SMatthew G. Knepley 
4360e91fa0a1SMatthew G. Knepley     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4361e91fa0a1SMatthew G. Knepley     while (qEnd > qStart) {
4362e91fa0a1SMatthew G. Knepley       PetscInt sMin = PETSC_MAX_INT;
4363e91fa0a1SMatthew G. Knepley       PetscInt sMax = PETSC_MIN_INT;
4364e91fa0a1SMatthew G. Knepley 
4365e91fa0a1SMatthew G. Knepley       for (PetscInt q = qStart; q < qEnd; ++q) {
4366e91fa0a1SMatthew G. Knepley         const PetscInt *support;
4367e91fa0a1SMatthew G. Knepley         PetscInt        supportSize;
4368e91fa0a1SMatthew G. Knepley 
4369e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4370e91fa0a1SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, q, &support));
4371e91fa0a1SMatthew G. Knepley         for (PetscInt s = 0; s < supportSize; ++s) {
4372e91fa0a1SMatthew G. Knepley           sMin = PetscMin(support[s], sMin);
4373e91fa0a1SMatthew G. Knepley           sMax = PetscMax(support[s], sMax);
4374e91fa0a1SMatthew G. Knepley         }
4375e91fa0a1SMatthew G. Knepley       }
4376e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetNumValues(label, &level));
4377e91fa0a1SMatthew G. Knepley       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4378e91fa0a1SMatthew G. Knepley       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4379e91fa0a1SMatthew G. Knepley     }
4380e91fa0a1SMatthew G. Knepley   }
4381e91fa0a1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
4382e91fa0a1SMatthew G. Knepley }
4383e91fa0a1SMatthew G. Knepley 
4384552f7358SJed Brown /*@
4385a4e35b19SJacob Faibussowitsch   DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4386552f7358SJed Brown 
438720f4b53cSBarry Smith   Collective
4388552f7358SJed Brown 
4389552f7358SJed Brown   Input Parameter:
439060225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4391552f7358SJed Brown 
4392a1cb98faSBarry Smith   Level: beginner
4393552f7358SJed Brown 
4394552f7358SJed Brown   Notes:
4395a4e35b19SJacob Faibussowitsch   The strata group all points of the same grade, and this function calculates the strata. This
4396a4e35b19SJacob Faibussowitsch   grade can be seen as the height (or depth) of the point in the DAG.
4397a4e35b19SJacob Faibussowitsch 
4398a4e35b19SJacob Faibussowitsch   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4399a4e35b19SJacob Faibussowitsch   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4400a1cb98faSBarry Smith   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4401b1bb481bSMatthew 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
4402a1cb98faSBarry Smith   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4403a1cb98faSBarry Smith   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4404a1cb98faSBarry Smith   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.
4405552f7358SJed Brown 
4406b1bb481bSMatthew Knepley   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4407b1bb481bSMatthew Knepley   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4408b1bb481bSMatthew 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
4409b1bb481bSMatthew Knepley   to interpolate only that one (e0), so that
4410a1cb98faSBarry Smith .vb
4411a1cb98faSBarry Smith   cone(c0) = {e0, v2}
4412a1cb98faSBarry Smith   cone(e0) = {v0, v1}
4413a1cb98faSBarry Smith .ve
4414a1cb98faSBarry Smith   If `DMPlexStratify()` is run on this mesh, it will give depths
4415a1cb98faSBarry Smith .vb
4416a1cb98faSBarry Smith    depth 0 = {v0, v1, v2}
4417a1cb98faSBarry Smith    depth 1 = {e0, c0}
4418a1cb98faSBarry Smith .ve
4419b1bb481bSMatthew Knepley   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4420b1bb481bSMatthew Knepley 
4421a1cb98faSBarry Smith   `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4422552f7358SJed Brown 
44231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4424552f7358SJed Brown @*/
4425d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratify(DM dm)
4426d71ae5a4SJacob Faibussowitsch {
4427df0420ecSMatthew G. Knepley   DM_Plex  *mesh = (DM_Plex *)dm->data;
4428aa50250dSMatthew G. Knepley   DMLabel   label;
4429e91fa0a1SMatthew G. Knepley   PetscBool flg = PETSC_FALSE;
4430552f7358SJed Brown 
4431552f7358SJed Brown   PetscFunctionBegin;
4432552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
44339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4434277ea44aSLisandro Dalcin 
4435e91fa0a1SMatthew G. Knepley   // Create depth label
44369566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "depth"));
44379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
4438277ea44aSLisandro Dalcin 
4439e91fa0a1SMatthew G. Knepley   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL));
4440e91fa0a1SMatthew G. Knepley   if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label));
4441e91fa0a1SMatthew G. Knepley   else PetscCall(DMPlexStratify_Topological_Private(dm, label));
4442552f7358SJed Brown 
4443bf4602e4SToby Isaac   { /* just in case there is an empty process */
4444bf4602e4SToby Isaac     PetscInt numValues, maxValues = 0, v;
4445bf4602e4SToby Isaac 
44469566063dSJacob Faibussowitsch     PetscCall(DMLabelGetNumValues(label, &numValues));
4447712fec58SPierre Jolivet     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
444848a46eb9SPierre Jolivet     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4449bf4602e4SToby Isaac   }
44509566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
44519566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
44523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4453552f7358SJed Brown }
4454552f7358SJed Brown 
4455d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4456d71ae5a4SJacob Faibussowitsch {
4457412e9a14SMatthew G. Knepley   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4458412e9a14SMatthew G. Knepley   PetscInt       dim, depth, pheight, coneSize;
4459ba2698f1SMatthew G. Knepley 
4460412e9a14SMatthew G. Knepley   PetscFunctionBeginHot;
44619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
44629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
44639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4464ba2698f1SMatthew G. Knepley   pheight = depth - pdepth;
4465ba2698f1SMatthew G. Knepley   if (depth <= 1) {
4466ba2698f1SMatthew G. Knepley     switch (pdepth) {
4467d71ae5a4SJacob Faibussowitsch     case 0:
4468d71ae5a4SJacob Faibussowitsch       ct = DM_POLYTOPE_POINT;
4469d71ae5a4SJacob Faibussowitsch       break;
4470ba2698f1SMatthew G. Knepley     case 1:
4471ba2698f1SMatthew G. Knepley       switch (coneSize) {
4472d71ae5a4SJacob Faibussowitsch       case 2:
4473d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4474d71ae5a4SJacob Faibussowitsch         break;
4475d71ae5a4SJacob Faibussowitsch       case 3:
4476d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4477d71ae5a4SJacob Faibussowitsch         break;
4478ba2698f1SMatthew G. Knepley       case 4:
4479ba2698f1SMatthew G. Knepley         switch (dim) {
4480d71ae5a4SJacob Faibussowitsch         case 2:
4481d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4482d71ae5a4SJacob Faibussowitsch           break;
4483d71ae5a4SJacob Faibussowitsch         case 3:
4484d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4485d71ae5a4SJacob Faibussowitsch           break;
4486d71ae5a4SJacob Faibussowitsch         default:
4487d71ae5a4SJacob Faibussowitsch           break;
4488ba2698f1SMatthew G. Knepley         }
4489ba2698f1SMatthew G. Knepley         break;
4490d71ae5a4SJacob Faibussowitsch       case 5:
4491d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_PYRAMID;
4492d71ae5a4SJacob Faibussowitsch         break;
4493d71ae5a4SJacob Faibussowitsch       case 6:
4494d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4495d71ae5a4SJacob Faibussowitsch         break;
4496d71ae5a4SJacob Faibussowitsch       case 8:
4497d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_HEXAHEDRON;
4498d71ae5a4SJacob Faibussowitsch         break;
4499d71ae5a4SJacob Faibussowitsch       default:
4500d71ae5a4SJacob Faibussowitsch         break;
4501ba2698f1SMatthew G. Knepley       }
4502ba2698f1SMatthew G. Knepley     }
4503ba2698f1SMatthew G. Knepley   } else {
4504ba2698f1SMatthew G. Knepley     if (pdepth == 0) {
4505ba2698f1SMatthew G. Knepley       ct = DM_POLYTOPE_POINT;
4506ba2698f1SMatthew G. Knepley     } else if (pheight == 0) {
4507ba2698f1SMatthew G. Knepley       switch (dim) {
4508ba2698f1SMatthew G. Knepley       case 1:
4509ba2698f1SMatthew G. Knepley         switch (coneSize) {
4510d71ae5a4SJacob Faibussowitsch         case 2:
4511d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_SEGMENT;
4512d71ae5a4SJacob Faibussowitsch           break;
4513d71ae5a4SJacob Faibussowitsch         default:
4514d71ae5a4SJacob Faibussowitsch           break;
4515ba2698f1SMatthew G. Knepley         }
4516ba2698f1SMatthew G. Knepley         break;
4517ba2698f1SMatthew G. Knepley       case 2:
4518ba2698f1SMatthew G. Knepley         switch (coneSize) {
4519d71ae5a4SJacob Faibussowitsch         case 3:
4520d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TRIANGLE;
4521d71ae5a4SJacob Faibussowitsch           break;
4522d71ae5a4SJacob Faibussowitsch         case 4:
4523d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_QUADRILATERAL;
4524d71ae5a4SJacob Faibussowitsch           break;
4525d71ae5a4SJacob Faibussowitsch         default:
4526d71ae5a4SJacob Faibussowitsch           break;
4527ba2698f1SMatthew G. Knepley         }
4528ba2698f1SMatthew G. Knepley         break;
4529ba2698f1SMatthew G. Knepley       case 3:
4530ba2698f1SMatthew G. Knepley         switch (coneSize) {
4531d71ae5a4SJacob Faibussowitsch         case 4:
4532d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_TETRAHEDRON;
4533d71ae5a4SJacob Faibussowitsch           break;
45349371c9d4SSatish Balay         case 5: {
4535da9060c4SMatthew G. Knepley           const PetscInt *cone;
4536da9060c4SMatthew G. Knepley           PetscInt        faceConeSize;
4537da9060c4SMatthew G. Knepley 
45389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, p, &cone));
45399566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4540da9060c4SMatthew G. Knepley           switch (faceConeSize) {
4541d71ae5a4SJacob Faibussowitsch           case 3:
4542d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4543d71ae5a4SJacob Faibussowitsch             break;
4544d71ae5a4SJacob Faibussowitsch           case 4:
4545d71ae5a4SJacob Faibussowitsch             ct = DM_POLYTOPE_PYRAMID;
4546d71ae5a4SJacob Faibussowitsch             break;
4547da9060c4SMatthew G. Knepley           }
45489371c9d4SSatish Balay         } break;
4549d71ae5a4SJacob Faibussowitsch         case 6:
4550d71ae5a4SJacob Faibussowitsch           ct = DM_POLYTOPE_HEXAHEDRON;
4551d71ae5a4SJacob Faibussowitsch           break;
4552d71ae5a4SJacob Faibussowitsch         default:
4553d71ae5a4SJacob Faibussowitsch           break;
4554ba2698f1SMatthew G. Knepley         }
4555ba2698f1SMatthew G. Knepley         break;
4556d71ae5a4SJacob Faibussowitsch       default:
4557d71ae5a4SJacob Faibussowitsch         break;
4558ba2698f1SMatthew G. Knepley       }
4559ba2698f1SMatthew G. Knepley     } else if (pheight > 0) {
4560ba2698f1SMatthew G. Knepley       switch (coneSize) {
4561d71ae5a4SJacob Faibussowitsch       case 2:
4562d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_SEGMENT;
4563d71ae5a4SJacob Faibussowitsch         break;
4564d71ae5a4SJacob Faibussowitsch       case 3:
4565d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_TRIANGLE;
4566d71ae5a4SJacob Faibussowitsch         break;
4567d71ae5a4SJacob Faibussowitsch       case 4:
4568d71ae5a4SJacob Faibussowitsch         ct = DM_POLYTOPE_QUADRILATERAL;
4569d71ae5a4SJacob Faibussowitsch         break;
4570d71ae5a4SJacob Faibussowitsch       default:
4571d71ae5a4SJacob Faibussowitsch         break;
4572ba2698f1SMatthew G. Knepley       }
4573ba2698f1SMatthew G. Knepley     }
4574ba2698f1SMatthew G. Knepley   }
4575412e9a14SMatthew G. Knepley   *pt = ct;
45763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4577ba2698f1SMatthew G. Knepley }
4578412e9a14SMatthew G. Knepley 
4579412e9a14SMatthew G. Knepley /*@
4580412e9a14SMatthew G. Knepley   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4581412e9a14SMatthew G. Knepley 
458220f4b53cSBarry Smith   Collective
4583412e9a14SMatthew G. Knepley 
4584412e9a14SMatthew G. Knepley   Input Parameter:
458560225df5SJacob Faibussowitsch . dm - The `DMPLEX`
4586412e9a14SMatthew G. Knepley 
4587412e9a14SMatthew G. Knepley   Level: developer
4588412e9a14SMatthew G. Knepley 
4589a1cb98faSBarry Smith   Note:
4590a1cb98faSBarry Smith   This function is normally called automatically when a cell type is requested. It creates an
4591a1cb98faSBarry Smith   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4592a1cb98faSBarry Smith   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4593412e9a14SMatthew G. Knepley 
4594a1cb98faSBarry Smith   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4595a1cb98faSBarry Smith 
45961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4597412e9a14SMatthew G. Knepley @*/
4598d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellTypes(DM dm)
4599d71ae5a4SJacob Faibussowitsch {
4600412e9a14SMatthew G. Knepley   DM_Plex *mesh;
4601412e9a14SMatthew G. Knepley   DMLabel  ctLabel;
4602412e9a14SMatthew G. Knepley   PetscInt pStart, pEnd, p;
4603412e9a14SMatthew G. Knepley 
4604412e9a14SMatthew G. Knepley   PetscFunctionBegin;
4605412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4606412e9a14SMatthew G. Knepley   mesh = (DM_Plex *)dm->data;
46079566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
46089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
46099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
461021027e53SStefano Zampini   PetscCall(PetscFree(mesh->cellTypes));
461121027e53SStefano Zampini   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4612412e9a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
4613327c2912SStefano Zampini     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4614412e9a14SMatthew G. Knepley     PetscInt       pdepth;
4615412e9a14SMatthew G. Knepley 
46169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
46179566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4618476787b7SMatthew 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);
46199566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(ctLabel, p, ct));
462021027e53SStefano Zampini     mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4621412e9a14SMatthew G. Knepley   }
46229566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
46239566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
46243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4625ba2698f1SMatthew G. Knepley }
4626ba2698f1SMatthew G. Knepley 
4627552f7358SJed Brown /*@C
4628552f7358SJed Brown   DMPlexGetJoin - Get an array for the join of the set of points
4629552f7358SJed Brown 
4630552f7358SJed Brown   Not Collective
4631552f7358SJed Brown 
4632552f7358SJed Brown   Input Parameters:
4633a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4634552f7358SJed Brown . numPoints - The number of input points for the join
4635552f7358SJed Brown - points    - The input points
4636552f7358SJed Brown 
4637552f7358SJed Brown   Output Parameters:
4638552f7358SJed Brown + numCoveredPoints - The number of points in the join
4639552f7358SJed Brown - coveredPoints    - The points in the join
4640552f7358SJed Brown 
4641552f7358SJed Brown   Level: intermediate
4642552f7358SJed Brown 
4643a1cb98faSBarry Smith   Note:
4644a1cb98faSBarry Smith   Currently, this is restricted to a single level join
4645552f7358SJed Brown 
464660225df5SJacob Faibussowitsch   Fortran Notes:
464720f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
46483813dfbdSMatthew G Knepley 
46491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4650552f7358SJed Brown @*/
4651d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4652d71ae5a4SJacob Faibussowitsch {
4653552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4654552f7358SJed Brown   PetscInt *join[2];
4655552f7358SJed Brown   PetscInt  joinSize, i = 0;
4656552f7358SJed Brown   PetscInt  dof, off, p, c, m;
46576302a7fbSVaclav Hapla   PetscInt  maxSupportSize;
4658552f7358SJed Brown 
4659552f7358SJed Brown   PetscFunctionBegin;
4660552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
46614f572ea9SToby Isaac   PetscAssertPointer(points, 3);
46624f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
46634f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
46646302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
46656302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
46666302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4667552f7358SJed Brown   /* Copy in support of first point */
46689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
46699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4670ad540459SPierre Jolivet   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4671552f7358SJed Brown   /* Check each successive support */
4672552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4673552f7358SJed Brown     PetscInt newJoinSize = 0;
4674552f7358SJed Brown 
46759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
46769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4677552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4678552f7358SJed Brown       const PetscInt point = mesh->supports[off + c];
4679552f7358SJed Brown 
4680552f7358SJed Brown       for (m = 0; m < joinSize; ++m) {
4681552f7358SJed Brown         if (point == join[i][m]) {
4682552f7358SJed Brown           join[1 - i][newJoinSize++] = point;
4683552f7358SJed Brown           break;
4684552f7358SJed Brown         }
4685552f7358SJed Brown       }
4686552f7358SJed Brown     }
4687552f7358SJed Brown     joinSize = newJoinSize;
4688552f7358SJed Brown     i        = 1 - i;
4689552f7358SJed Brown   }
4690552f7358SJed Brown   *numCoveredPoints = joinSize;
4691552f7358SJed Brown   *coveredPoints    = join[i];
46926302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
46933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4694552f7358SJed Brown }
4695552f7358SJed Brown 
4696552f7358SJed Brown /*@C
4697552f7358SJed Brown   DMPlexRestoreJoin - Restore an array for the join of the set of points
4698552f7358SJed Brown 
4699552f7358SJed Brown   Not Collective
4700552f7358SJed Brown 
4701552f7358SJed Brown   Input Parameters:
4702a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4703552f7358SJed Brown . numPoints - The number of input points for the join
4704552f7358SJed Brown - points    - The input points
4705552f7358SJed Brown 
4706552f7358SJed Brown   Output Parameters:
4707552f7358SJed Brown + numCoveredPoints - The number of points in the join
4708552f7358SJed Brown - coveredPoints    - The points in the join
4709552f7358SJed Brown 
4710552f7358SJed Brown   Level: intermediate
4711552f7358SJed Brown 
471260225df5SJacob Faibussowitsch   Fortran Notes:
471320f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4714a1cb98faSBarry Smith 
47151cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4716552f7358SJed Brown @*/
4717d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4718d71ae5a4SJacob Faibussowitsch {
4719552f7358SJed Brown   PetscFunctionBegin;
4720552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47214f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
47224f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
47234f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
47249566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4725d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
47263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4727552f7358SJed Brown }
4728552f7358SJed Brown 
4729552f7358SJed Brown /*@C
4730552f7358SJed Brown   DMPlexGetFullJoin - Get an array for the join of the set of points
4731552f7358SJed Brown 
4732552f7358SJed Brown   Not Collective
4733552f7358SJed Brown 
4734552f7358SJed Brown   Input Parameters:
4735a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4736552f7358SJed Brown . numPoints - The number of input points for the join
4737552f7358SJed Brown - points    - The input points
4738552f7358SJed Brown 
4739552f7358SJed Brown   Output Parameters:
4740552f7358SJed Brown + numCoveredPoints - The number of points in the join
4741552f7358SJed Brown - coveredPoints    - The points in the join
4742552f7358SJed Brown 
4743552f7358SJed Brown   Level: intermediate
4744552f7358SJed Brown 
474560225df5SJacob Faibussowitsch   Fortran Notes:
474620f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4747a1cb98faSBarry Smith 
47481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4749552f7358SJed Brown @*/
4750d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4751d71ae5a4SJacob Faibussowitsch {
4752552f7358SJed Brown   PetscInt *offsets, **closures;
4753552f7358SJed Brown   PetscInt *join[2];
4754552f7358SJed Brown   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
475524c766afSToby Isaac   PetscInt  p, d, c, m, ms;
4756552f7358SJed Brown 
4757552f7358SJed Brown   PetscFunctionBegin;
4758552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47594f572ea9SToby Isaac   PetscAssertPointer(points, 3);
47604f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
47614f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4762552f7358SJed Brown 
47639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
47649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numPoints, &closures));
47659566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
47666302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
476724c766afSToby Isaac   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
47689566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
47699566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4770552f7358SJed Brown 
4771552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4772552f7358SJed Brown     PetscInt closureSize;
4773552f7358SJed Brown 
47749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
47750d644c17SKarl Rupp 
4776552f7358SJed Brown     offsets[p * (depth + 2) + 0] = 0;
4777552f7358SJed Brown     for (d = 0; d < depth + 1; ++d) {
4778552f7358SJed Brown       PetscInt pStart, pEnd, i;
4779552f7358SJed Brown 
47809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4781552f7358SJed Brown       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4782552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4783552f7358SJed Brown           offsets[p * (depth + 2) + d + 1] = i;
4784552f7358SJed Brown           break;
4785552f7358SJed Brown         }
4786552f7358SJed Brown       }
4787552f7358SJed Brown       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4788552f7358SJed Brown     }
478963a3b9bcSJacob 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);
4790552f7358SJed Brown   }
4791552f7358SJed Brown   for (d = 0; d < depth + 1; ++d) {
4792552f7358SJed Brown     PetscInt dof;
4793552f7358SJed Brown 
4794552f7358SJed Brown     /* Copy in support of first point */
4795552f7358SJed Brown     dof = offsets[d + 1] - offsets[d];
4796ad540459SPierre Jolivet     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4797552f7358SJed Brown     /* Check each successive cone */
4798552f7358SJed Brown     for (p = 1; p < numPoints && joinSize; ++p) {
4799552f7358SJed Brown       PetscInt newJoinSize = 0;
4800552f7358SJed Brown 
4801552f7358SJed Brown       dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
4802552f7358SJed Brown       for (c = 0; c < dof; ++c) {
4803552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
4804552f7358SJed Brown 
4805552f7358SJed Brown         for (m = 0; m < joinSize; ++m) {
4806552f7358SJed Brown           if (point == join[i][m]) {
4807552f7358SJed Brown             join[1 - i][newJoinSize++] = point;
4808552f7358SJed Brown             break;
4809552f7358SJed Brown           }
4810552f7358SJed Brown         }
4811552f7358SJed Brown       }
4812552f7358SJed Brown       joinSize = newJoinSize;
4813552f7358SJed Brown       i        = 1 - i;
4814552f7358SJed Brown     }
4815552f7358SJed Brown     if (joinSize) break;
4816552f7358SJed Brown   }
4817552f7358SJed Brown   *numCoveredPoints = joinSize;
4818552f7358SJed Brown   *coveredPoints    = join[i];
481948a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
48209566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
48219566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
48226302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
48233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4824552f7358SJed Brown }
4825552f7358SJed Brown 
4826552f7358SJed Brown /*@C
4827552f7358SJed Brown   DMPlexGetMeet - Get an array for the meet of the set of points
4828552f7358SJed Brown 
4829552f7358SJed Brown   Not Collective
4830552f7358SJed Brown 
4831552f7358SJed Brown   Input Parameters:
4832a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4833552f7358SJed Brown . numPoints - The number of input points for the meet
4834552f7358SJed Brown - points    - The input points
4835552f7358SJed Brown 
4836552f7358SJed Brown   Output Parameters:
483760225df5SJacob Faibussowitsch + numCoveringPoints - The number of points in the meet
483860225df5SJacob Faibussowitsch - coveringPoints    - The points in the meet
4839552f7358SJed Brown 
4840552f7358SJed Brown   Level: intermediate
4841552f7358SJed Brown 
4842a1cb98faSBarry Smith   Note:
4843a1cb98faSBarry Smith   Currently, this is restricted to a single level meet
4844552f7358SJed Brown 
48453813dfbdSMatthew G Knepley   Fortran Notes:
484620f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
48473813dfbdSMatthew G Knepley 
48481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4849552f7358SJed Brown @*/
4850d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4851d71ae5a4SJacob Faibussowitsch {
4852552f7358SJed Brown   DM_Plex  *mesh = (DM_Plex *)dm->data;
4853552f7358SJed Brown   PetscInt *meet[2];
4854552f7358SJed Brown   PetscInt  meetSize, i = 0;
4855552f7358SJed Brown   PetscInt  dof, off, p, c, m;
48566302a7fbSVaclav Hapla   PetscInt  maxConeSize;
4857552f7358SJed Brown 
4858552f7358SJed Brown   PetscFunctionBegin;
4859552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48604f572ea9SToby Isaac   PetscAssertPointer(points, 3);
48614f572ea9SToby Isaac   PetscAssertPointer(numCoveringPoints, 4);
48624f572ea9SToby Isaac   PetscAssertPointer(coveringPoints, 5);
48636302a7fbSVaclav Hapla   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
48646302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
48656302a7fbSVaclav Hapla   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4866552f7358SJed Brown   /* Copy in cone of first point */
48679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
48689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4869ad540459SPierre Jolivet   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4870552f7358SJed Brown   /* Check each successive cone */
4871552f7358SJed Brown   for (p = 1; p < numPoints; ++p) {
4872552f7358SJed Brown     PetscInt newMeetSize = 0;
4873552f7358SJed Brown 
48749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
48759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4876552f7358SJed Brown     for (c = 0; c < dof; ++c) {
4877552f7358SJed Brown       const PetscInt point = mesh->cones[off + c];
4878552f7358SJed Brown 
4879552f7358SJed Brown       for (m = 0; m < meetSize; ++m) {
4880552f7358SJed Brown         if (point == meet[i][m]) {
4881552f7358SJed Brown           meet[1 - i][newMeetSize++] = point;
4882552f7358SJed Brown           break;
4883552f7358SJed Brown         }
4884552f7358SJed Brown       }
4885552f7358SJed Brown     }
4886552f7358SJed Brown     meetSize = newMeetSize;
4887552f7358SJed Brown     i        = 1 - i;
4888552f7358SJed Brown   }
4889552f7358SJed Brown   *numCoveringPoints = meetSize;
4890552f7358SJed Brown   *coveringPoints    = meet[i];
48916302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
48923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4893552f7358SJed Brown }
4894552f7358SJed Brown 
4895552f7358SJed Brown /*@C
4896552f7358SJed Brown   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4897552f7358SJed Brown 
4898552f7358SJed Brown   Not Collective
4899552f7358SJed Brown 
4900552f7358SJed Brown   Input Parameters:
4901a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4902552f7358SJed Brown . numPoints - The number of input points for the meet
4903552f7358SJed Brown - points    - The input points
4904552f7358SJed Brown 
4905552f7358SJed Brown   Output Parameters:
4906552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4907552f7358SJed Brown - coveredPoints    - The points in the meet
4908552f7358SJed Brown 
4909552f7358SJed Brown   Level: intermediate
4910552f7358SJed Brown 
491160225df5SJacob Faibussowitsch   Fortran Notes:
491220f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
49133813dfbdSMatthew G Knepley 
49141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4915552f7358SJed Brown @*/
4916d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4917d71ae5a4SJacob Faibussowitsch {
4918552f7358SJed Brown   PetscFunctionBegin;
4919552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49204f572ea9SToby Isaac   if (points) PetscAssertPointer(points, 3);
49214f572ea9SToby Isaac   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
49224f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
49239566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4924d7902bd2SMatthew G. Knepley   if (numCoveredPoints) *numCoveredPoints = 0;
49253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4926552f7358SJed Brown }
4927552f7358SJed Brown 
4928552f7358SJed Brown /*@C
4929552f7358SJed Brown   DMPlexGetFullMeet - Get an array for the meet of the set of points
4930552f7358SJed Brown 
4931552f7358SJed Brown   Not Collective
4932552f7358SJed Brown 
4933552f7358SJed Brown   Input Parameters:
4934a1cb98faSBarry Smith + dm        - The `DMPLEX` object
4935552f7358SJed Brown . numPoints - The number of input points for the meet
4936552f7358SJed Brown - points    - The input points
4937552f7358SJed Brown 
4938552f7358SJed Brown   Output Parameters:
4939552f7358SJed Brown + numCoveredPoints - The number of points in the meet
4940552f7358SJed Brown - coveredPoints    - The points in the meet
4941552f7358SJed Brown 
4942552f7358SJed Brown   Level: intermediate
4943552f7358SJed Brown 
494460225df5SJacob Faibussowitsch   Fortran Notes:
494520f4b53cSBarry Smith   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
49463813dfbdSMatthew G Knepley 
49471cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4948552f7358SJed Brown @*/
4949d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4950d71ae5a4SJacob Faibussowitsch {
4951552f7358SJed Brown   PetscInt *offsets, **closures;
4952552f7358SJed Brown   PetscInt *meet[2];
4953552f7358SJed Brown   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
495424c766afSToby Isaac   PetscInt  p, h, c, m, mc;
4955552f7358SJed Brown 
4956552f7358SJed Brown   PetscFunctionBegin;
4957552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49584f572ea9SToby Isaac   PetscAssertPointer(points, 3);
49594f572ea9SToby Isaac   PetscAssertPointer(numCoveredPoints, 4);
49604f572ea9SToby Isaac   PetscAssertPointer(coveredPoints, 5);
4961552f7358SJed Brown 
49629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &height));
49639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &closures));
49649566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
49656302a7fbSVaclav Hapla   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
496624c766afSToby Isaac   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
49679566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
49689566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4969552f7358SJed Brown 
4970552f7358SJed Brown   for (p = 0; p < numPoints; ++p) {
4971552f7358SJed Brown     PetscInt closureSize;
4972552f7358SJed Brown 
49739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
49740d644c17SKarl Rupp 
4975552f7358SJed Brown     offsets[p * (height + 2) + 0] = 0;
4976552f7358SJed Brown     for (h = 0; h < height + 1; ++h) {
4977552f7358SJed Brown       PetscInt pStart, pEnd, i;
4978552f7358SJed Brown 
49799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4980552f7358SJed Brown       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
4981552f7358SJed Brown         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4982552f7358SJed Brown           offsets[p * (height + 2) + h + 1] = i;
4983552f7358SJed Brown           break;
4984552f7358SJed Brown         }
4985552f7358SJed Brown       }
4986552f7358SJed Brown       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
4987552f7358SJed Brown     }
498863a3b9bcSJacob 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);
4989552f7358SJed Brown   }
4990552f7358SJed Brown   for (h = 0; h < height + 1; ++h) {
4991552f7358SJed Brown     PetscInt dof;
4992552f7358SJed Brown 
4993552f7358SJed Brown     /* Copy in cone of first point */
4994552f7358SJed Brown     dof = offsets[h + 1] - offsets[h];
4995ad540459SPierre Jolivet     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
4996552f7358SJed Brown     /* Check each successive cone */
4997552f7358SJed Brown     for (p = 1; p < numPoints && meetSize; ++p) {
4998552f7358SJed Brown       PetscInt newMeetSize = 0;
4999552f7358SJed Brown 
5000552f7358SJed Brown       dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
5001552f7358SJed Brown       for (c = 0; c < dof; ++c) {
5002552f7358SJed Brown         const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
5003552f7358SJed Brown 
5004552f7358SJed Brown         for (m = 0; m < meetSize; ++m) {
5005552f7358SJed Brown           if (point == meet[i][m]) {
5006552f7358SJed Brown             meet[1 - i][newMeetSize++] = point;
5007552f7358SJed Brown             break;
5008552f7358SJed Brown           }
5009552f7358SJed Brown         }
5010552f7358SJed Brown       }
5011552f7358SJed Brown       meetSize = newMeetSize;
5012552f7358SJed Brown       i        = 1 - i;
5013552f7358SJed Brown     }
5014552f7358SJed Brown     if (meetSize) break;
5015552f7358SJed Brown   }
5016552f7358SJed Brown   *numCoveredPoints = meetSize;
5017552f7358SJed Brown   *coveredPoints    = meet[i];
501848a46eb9SPierre Jolivet   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
50199566063dSJacob Faibussowitsch   PetscCall(PetscFree(closures));
50209566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
50216302a7fbSVaclav Hapla   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
50223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5023552f7358SJed Brown }
5024552f7358SJed Brown 
50254e3744c5SMatthew G. Knepley /*@C
5026a1cb98faSBarry Smith   DMPlexEqual - Determine if two `DM` have the same topology
50274e3744c5SMatthew G. Knepley 
50284e3744c5SMatthew G. Knepley   Not Collective
50294e3744c5SMatthew G. Knepley 
50304e3744c5SMatthew G. Knepley   Input Parameters:
5031a1cb98faSBarry Smith + dmA - A `DMPLEX` object
5032a1cb98faSBarry Smith - dmB - A `DMPLEX` object
50334e3744c5SMatthew G. Knepley 
50342fe279fdSBarry Smith   Output Parameter:
5035a1cb98faSBarry Smith . equal - `PETSC_TRUE` if the topologies are identical
50364e3744c5SMatthew G. Knepley 
50374e3744c5SMatthew G. Knepley   Level: intermediate
50384e3744c5SMatthew G. Knepley 
5039a1cb98faSBarry Smith   Note:
50403c7db156SBarry Smith   We are not solving graph isomorphism, so we do not permute.
50414e3744c5SMatthew G. Knepley 
50421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
50434e3744c5SMatthew G. Knepley @*/
5044d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
5045d71ae5a4SJacob Faibussowitsch {
50464e3744c5SMatthew G. Knepley   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
50474e3744c5SMatthew G. Knepley 
50484e3744c5SMatthew G. Knepley   PetscFunctionBegin;
50494e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
50504e3744c5SMatthew G. Knepley   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
50514f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
50524e3744c5SMatthew G. Knepley 
50534e3744c5SMatthew G. Knepley   *equal = PETSC_FALSE;
50549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmA, &depth));
50559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmB, &depthB));
50563ba16761SJacob Faibussowitsch   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
50579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
50589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
50593ba16761SJacob Faibussowitsch   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
50604e3744c5SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
50614e3744c5SMatthew G. Knepley     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
50624e3744c5SMatthew G. Knepley     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
50634e3744c5SMatthew G. Knepley 
50649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
50659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmA, p, &cone));
50669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
50679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
50689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmB, p, &coneB));
50699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
50703ba16761SJacob Faibussowitsch     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
50714e3744c5SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
50723ba16761SJacob Faibussowitsch       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
50733ba16761SJacob Faibussowitsch       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
50744e3744c5SMatthew G. Knepley     }
50759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
50769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmA, p, &support));
50779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
50789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
50793ba16761SJacob Faibussowitsch     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
50804e3744c5SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
50813ba16761SJacob Faibussowitsch       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
50824e3744c5SMatthew G. Knepley     }
50834e3744c5SMatthew G. Knepley   }
50844e3744c5SMatthew G. Knepley   *equal = PETSC_TRUE;
50853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50864e3744c5SMatthew G. Knepley }
50874e3744c5SMatthew G. Knepley 
50887cd05799SMatthew G. Knepley /*@C
50897cd05799SMatthew G. Knepley   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
50907cd05799SMatthew G. Knepley 
50917cd05799SMatthew G. Knepley   Not Collective
50927cd05799SMatthew G. Knepley 
50937cd05799SMatthew G. Knepley   Input Parameters:
5094a1cb98faSBarry Smith + dm         - The `DMPLEX`
50957cd05799SMatthew G. Knepley . cellDim    - The cell dimension
50967cd05799SMatthew G. Knepley - numCorners - The number of vertices on a cell
50977cd05799SMatthew G. Knepley 
50982fe279fdSBarry Smith   Output Parameter:
50997cd05799SMatthew G. Knepley . numFaceVertices - The number of vertices on a face
51007cd05799SMatthew G. Knepley 
51017cd05799SMatthew G. Knepley   Level: developer
51027cd05799SMatthew G. Knepley 
5103a1cb98faSBarry Smith   Note:
51047cd05799SMatthew G. Knepley   Of course this can only work for a restricted set of symmetric shapes
51057cd05799SMatthew G. Knepley 
51061cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
51077cd05799SMatthew G. Knepley @*/
5108d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
5109d71ae5a4SJacob Faibussowitsch {
511082f516ccSBarry Smith   MPI_Comm comm;
5111552f7358SJed Brown 
5112552f7358SJed Brown   PetscFunctionBegin;
51139566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
51144f572ea9SToby Isaac   PetscAssertPointer(numFaceVertices, 4);
5115552f7358SJed Brown   switch (cellDim) {
5116d71ae5a4SJacob Faibussowitsch   case 0:
5117d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 0;
5118d71ae5a4SJacob Faibussowitsch     break;
5119d71ae5a4SJacob Faibussowitsch   case 1:
5120d71ae5a4SJacob Faibussowitsch     *numFaceVertices = 1;
5121d71ae5a4SJacob Faibussowitsch     break;
5122552f7358SJed Brown   case 2:
5123552f7358SJed Brown     switch (numCorners) {
512419436ca2SJed Brown     case 3:                 /* triangle */
512519436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5126552f7358SJed Brown       break;
512719436ca2SJed Brown     case 4:                 /* quadrilateral */
512819436ca2SJed Brown       *numFaceVertices = 2; /* Edge has 2 vertices */
5129552f7358SJed Brown       break;
513019436ca2SJed Brown     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
513119436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5132552f7358SJed Brown       break;
513319436ca2SJed Brown     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
513419436ca2SJed Brown       *numFaceVertices = 3; /* Edge has 3 vertices */
5135552f7358SJed Brown       break;
5136d71ae5a4SJacob Faibussowitsch     default:
5137d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5138552f7358SJed Brown     }
5139552f7358SJed Brown     break;
5140552f7358SJed Brown   case 3:
5141552f7358SJed Brown     switch (numCorners) {
514219436ca2SJed Brown     case 4:                 /* tetradehdron */
514319436ca2SJed Brown       *numFaceVertices = 3; /* Face has 3 vertices */
5144552f7358SJed Brown       break;
514519436ca2SJed Brown     case 6:                 /* tet cohesive cells */
514619436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5147552f7358SJed Brown       break;
514819436ca2SJed Brown     case 8:                 /* hexahedron */
514919436ca2SJed Brown       *numFaceVertices = 4; /* Face has 4 vertices */
5150552f7358SJed Brown       break;
515119436ca2SJed Brown     case 9:                 /* tet cohesive Lagrange cells */
515219436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5153552f7358SJed Brown       break;
515419436ca2SJed Brown     case 10:                /* quadratic tetrahedron */
515519436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5156552f7358SJed Brown       break;
515719436ca2SJed Brown     case 12:                /* hex cohesive Lagrange cells */
515819436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5159552f7358SJed Brown       break;
516019436ca2SJed Brown     case 18:                /* quadratic tet cohesive Lagrange cells */
516119436ca2SJed Brown       *numFaceVertices = 6; /* Face has 6 vertices */
5162552f7358SJed Brown       break;
516319436ca2SJed Brown     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
516419436ca2SJed Brown       *numFaceVertices = 9; /* Face has 9 vertices */
5165552f7358SJed Brown       break;
5166d71ae5a4SJacob Faibussowitsch     default:
5167d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
5168552f7358SJed Brown     }
5169552f7358SJed Brown     break;
5170d71ae5a4SJacob Faibussowitsch   default:
5171d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
5172552f7358SJed Brown   }
51733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5174552f7358SJed Brown }
5175552f7358SJed Brown 
5176552f7358SJed Brown /*@
5177a1cb98faSBarry Smith   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
5178552f7358SJed Brown 
5179552f7358SJed Brown   Not Collective
5180552f7358SJed Brown 
5181aa50250dSMatthew G. Knepley   Input Parameter:
5182a1cb98faSBarry Smith . dm - The `DMPLEX` object
5183552f7358SJed Brown 
5184aa50250dSMatthew G. Knepley   Output Parameter:
5185a1cb98faSBarry Smith . depthLabel - The `DMLabel` recording point depth
5186552f7358SJed Brown 
5187552f7358SJed Brown   Level: developer
5188552f7358SJed Brown 
51891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
5190aa50250dSMatthew G. Knepley @*/
5191d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5192d71ae5a4SJacob Faibussowitsch {
5193aa50250dSMatthew G. Knepley   PetscFunctionBegin;
5194aa50250dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
51954f572ea9SToby Isaac   PetscAssertPointer(depthLabel, 2);
5196c58f1c22SToby Isaac   *depthLabel = dm->depthLabel;
51973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5198aa50250dSMatthew G. Knepley }
5199aa50250dSMatthew G. Knepley 
5200aa50250dSMatthew G. Knepley /*@
5201aa50250dSMatthew G. Knepley   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5202aa50250dSMatthew G. Knepley 
5203aa50250dSMatthew G. Knepley   Not Collective
5204aa50250dSMatthew G. Knepley 
5205aa50250dSMatthew G. Knepley   Input Parameter:
5206a1cb98faSBarry Smith . dm - The `DMPLEX` object
5207aa50250dSMatthew G. Knepley 
5208aa50250dSMatthew G. Knepley   Output Parameter:
5209aa50250dSMatthew G. Knepley . depth - The number of strata (breadth first levels) in the DAG
5210aa50250dSMatthew G. Knepley 
5211aa50250dSMatthew G. Knepley   Level: developer
5212552f7358SJed Brown 
5213b1bb481bSMatthew Knepley   Notes:
5214a1cb98faSBarry Smith   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
5215a1cb98faSBarry Smith 
5216a1cb98faSBarry Smith   The point depth is described more in detail in `DMPlexGetDepthStratum()`.
5217a1cb98faSBarry Smith 
5218dc287ab2SVaclav Hapla   An empty mesh gives -1.
5219b1bb481bSMatthew Knepley 
52201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
5221552f7358SJed Brown @*/
5222d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5223d71ae5a4SJacob Faibussowitsch {
52249f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5225aa50250dSMatthew G. Knepley   DMLabel  label;
5226aa50250dSMatthew G. Knepley   PetscInt d = 0;
5227552f7358SJed Brown 
5228552f7358SJed Brown   PetscFunctionBegin;
5229552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
52304f572ea9SToby Isaac   PetscAssertPointer(depth, 2);
52319f4ada15SMatthew G. Knepley   if (mesh->tr) {
52329f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
52339f4ada15SMatthew G. Knepley   } else {
52349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
52359566063dSJacob Faibussowitsch     if (label) PetscCall(DMLabelGetNumValues(label, &d));
5236552f7358SJed Brown     *depth = d - 1;
52379f4ada15SMatthew G. Knepley   }
52383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5239552f7358SJed Brown }
5240552f7358SJed Brown 
5241552f7358SJed Brown /*@
524220f4b53cSBarry Smith   DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5243552f7358SJed Brown 
5244552f7358SJed Brown   Not Collective
5245552f7358SJed Brown 
5246552f7358SJed Brown   Input Parameters:
5247a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5248570fa34dSVaclav Hapla - depth - The requested depth
5249552f7358SJed Brown 
5250552f7358SJed Brown   Output Parameters:
525120f4b53cSBarry Smith + start - The first point at this `depth`
525220f4b53cSBarry Smith - end   - One beyond the last point at this `depth`
5253552f7358SJed Brown 
5254552f7358SJed Brown   Level: developer
5255552f7358SJed Brown 
5256a1cb98faSBarry Smith   Notes:
5257a1cb98faSBarry Smith   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5258a1cb98faSBarry Smith   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5259a1cb98faSBarry Smith   higher dimension, e.g., "edges".
5260a1cb98faSBarry Smith 
52612827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5262552f7358SJed Brown @*/
5263d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5264d71ae5a4SJacob Faibussowitsch {
52659f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5266aa50250dSMatthew G. Knepley   DMLabel  label;
526763d1a920SMatthew G. Knepley   PetscInt pStart, pEnd;
5268552f7358SJed Brown 
5269552f7358SJed Brown   PetscFunctionBegin;
5270552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
52719371c9d4SSatish Balay   if (start) {
52724f572ea9SToby Isaac     PetscAssertPointer(start, 3);
52739371c9d4SSatish Balay     *start = 0;
52749371c9d4SSatish Balay   }
52759371c9d4SSatish Balay   if (end) {
52764f572ea9SToby Isaac     PetscAssertPointer(end, 4);
52779371c9d4SSatish Balay     *end = 0;
52789371c9d4SSatish Balay   }
52799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
52803ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5281570fa34dSVaclav Hapla   if (depth < 0) {
528263d1a920SMatthew G. Knepley     if (start) *start = pStart;
528363d1a920SMatthew G. Knepley     if (end) *end = pEnd;
52843ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5285552f7358SJed Brown   }
52869f4ada15SMatthew G. Knepley   if (mesh->tr) {
52879f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
52889f4ada15SMatthew G. Knepley   } else {
52899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dm, &label));
529028b400f6SJacob Faibussowitsch     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5291570fa34dSVaclav Hapla     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
52929f4ada15SMatthew G. Knepley   }
52933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5294552f7358SJed Brown }
5295552f7358SJed Brown 
5296552f7358SJed Brown /*@
529720f4b53cSBarry Smith   DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5298552f7358SJed Brown 
5299552f7358SJed Brown   Not Collective
5300552f7358SJed Brown 
5301552f7358SJed Brown   Input Parameters:
5302a1cb98faSBarry Smith + dm     - The `DMPLEX` object
5303570fa34dSVaclav Hapla - height - The requested height
5304552f7358SJed Brown 
5305552f7358SJed Brown   Output Parameters:
530620f4b53cSBarry Smith + start - The first point at this `height`
530720f4b53cSBarry Smith - end   - One beyond the last point at this `height`
5308552f7358SJed Brown 
5309552f7358SJed Brown   Level: developer
5310552f7358SJed Brown 
5311a1cb98faSBarry Smith   Notes:
5312a1cb98faSBarry Smith   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
5313a1cb98faSBarry Smith   points, often called "cells" or "elements".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5314a1cb98faSBarry Smith   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5315a1cb98faSBarry Smith 
53162827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5317552f7358SJed Brown @*/
5318d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5319d71ae5a4SJacob Faibussowitsch {
5320aa50250dSMatthew G. Knepley   DMLabel  label;
532163d1a920SMatthew G. Knepley   PetscInt depth, pStart, pEnd;
5322552f7358SJed Brown 
5323552f7358SJed Brown   PetscFunctionBegin;
5324552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53259371c9d4SSatish Balay   if (start) {
53264f572ea9SToby Isaac     PetscAssertPointer(start, 3);
53279371c9d4SSatish Balay     *start = 0;
53289371c9d4SSatish Balay   }
53299371c9d4SSatish Balay   if (end) {
53304f572ea9SToby Isaac     PetscAssertPointer(end, 4);
53319371c9d4SSatish Balay     *end = 0;
53329371c9d4SSatish Balay   }
53339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
53343ba16761SJacob Faibussowitsch   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5335570fa34dSVaclav Hapla   if (height < 0) {
533663d1a920SMatthew G. Knepley     if (start) *start = pStart;
533763d1a920SMatthew G. Knepley     if (end) *end = pEnd;
53383ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
5339552f7358SJed Brown   }
53409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
534159e4dc13SStefano Zampini   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
534259e4dc13SStefano Zampini   else PetscCall(DMGetDimension(dm, &depth));
534359e4dc13SStefano Zampini   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
534459e4dc13SStefano Zampini   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
53453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5346552f7358SJed Brown }
5347552f7358SJed Brown 
5348ba2698f1SMatthew G. Knepley /*@
534920f4b53cSBarry Smith   DMPlexGetPointDepth - Get the `depth` of a given point
5350ba2698f1SMatthew G. Knepley 
5351ba2698f1SMatthew G. Knepley   Not Collective
5352ba2698f1SMatthew G. Knepley 
5353d8d19677SJose E. Roman   Input Parameters:
5354a1cb98faSBarry Smith + dm    - The `DMPLEX` object
5355ba2698f1SMatthew G. Knepley - point - The point
5356ba2698f1SMatthew G. Knepley 
5357ba2698f1SMatthew G. Knepley   Output Parameter:
535820f4b53cSBarry Smith . depth - The depth of the `point`
5359ba2698f1SMatthew G. Knepley 
5360ba2698f1SMatthew G. Knepley   Level: intermediate
5361ba2698f1SMatthew G. Knepley 
53621cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5363ba2698f1SMatthew G. Knepley @*/
5364d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5365d71ae5a4SJacob Faibussowitsch {
5366ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5367ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53684f572ea9SToby Isaac   PetscAssertPointer(depth, 3);
53699566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
53703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5371ba2698f1SMatthew G. Knepley }
5372ba2698f1SMatthew G. Knepley 
5373ba2698f1SMatthew G. Knepley /*@
537420f4b53cSBarry Smith   DMPlexGetPointHeight - Get the `height` of a given point
53750c0a32dcSVaclav Hapla 
53760c0a32dcSVaclav Hapla   Not Collective
53770c0a32dcSVaclav Hapla 
5378d8d19677SJose E. Roman   Input Parameters:
5379a1cb98faSBarry Smith + dm    - The `DMPLEX` object
53800c0a32dcSVaclav Hapla - point - The point
53810c0a32dcSVaclav Hapla 
53820c0a32dcSVaclav Hapla   Output Parameter:
538320f4b53cSBarry Smith . height - The height of the `point`
53840c0a32dcSVaclav Hapla 
53850c0a32dcSVaclav Hapla   Level: intermediate
53860c0a32dcSVaclav Hapla 
53871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
53880c0a32dcSVaclav Hapla @*/
5389d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5390d71ae5a4SJacob Faibussowitsch {
53910c0a32dcSVaclav Hapla   PetscInt n, pDepth;
53920c0a32dcSVaclav Hapla 
53930c0a32dcSVaclav Hapla   PetscFunctionBegin;
53940c0a32dcSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53954f572ea9SToby Isaac   PetscAssertPointer(height, 3);
53969566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
53979566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
53980c0a32dcSVaclav Hapla   *height = n - 1 - pDepth; /* DAG depth is n-1 */
53993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54000c0a32dcSVaclav Hapla }
54010c0a32dcSVaclav Hapla 
54020c0a32dcSVaclav Hapla /*@
5403a1cb98faSBarry Smith   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5404ba2698f1SMatthew G. Knepley 
5405ba2698f1SMatthew G. Knepley   Not Collective
5406ba2698f1SMatthew G. Knepley 
5407ba2698f1SMatthew G. Knepley   Input Parameter:
5408a1cb98faSBarry Smith . dm - The `DMPLEX` object
5409ba2698f1SMatthew G. Knepley 
5410ba2698f1SMatthew G. Knepley   Output Parameter:
5411a1cb98faSBarry Smith . celltypeLabel - The `DMLabel` recording cell polytope type
5412412e9a14SMatthew G. Knepley 
5413ba2698f1SMatthew G. Knepley   Level: developer
5414ba2698f1SMatthew G. Knepley 
5415a1cb98faSBarry Smith   Note:
5416a1cb98faSBarry Smith   This function will trigger automatica computation of cell types. This can be disabled by calling
5417a1cb98faSBarry Smith   `DMCreateLabel`(dm, "celltype") beforehand.
5418a1cb98faSBarry Smith 
54191cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5420ba2698f1SMatthew G. Knepley @*/
5421d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5422d71ae5a4SJacob Faibussowitsch {
5423ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5424ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54254f572ea9SToby Isaac   PetscAssertPointer(celltypeLabel, 2);
54269566063dSJacob Faibussowitsch   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5427ba2698f1SMatthew G. Knepley   *celltypeLabel = dm->celltypeLabel;
54283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5429ba2698f1SMatthew G. Knepley }
5430ba2698f1SMatthew G. Knepley 
5431ba2698f1SMatthew G. Knepley /*@
5432ba2698f1SMatthew G. Knepley   DMPlexGetCellType - Get the polytope type of a given cell
5433ba2698f1SMatthew G. Knepley 
5434ba2698f1SMatthew G. Knepley   Not Collective
5435ba2698f1SMatthew G. Knepley 
5436d8d19677SJose E. Roman   Input Parameters:
5437a1cb98faSBarry Smith + dm   - The `DMPLEX` object
5438ba2698f1SMatthew G. Knepley - cell - The cell
5439ba2698f1SMatthew G. Knepley 
5440ba2698f1SMatthew G. Knepley   Output Parameter:
5441ba2698f1SMatthew G. Knepley . celltype - The polytope type of the cell
5442ba2698f1SMatthew G. Knepley 
5443ba2698f1SMatthew G. Knepley   Level: intermediate
5444ba2698f1SMatthew G. Knepley 
54451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5446ba2698f1SMatthew G. Knepley @*/
5447d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5448d71ae5a4SJacob Faibussowitsch {
54499f4ada15SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
5450ba2698f1SMatthew G. Knepley   DMLabel  label;
5451ba2698f1SMatthew G. Knepley   PetscInt ct;
5452ba2698f1SMatthew G. Knepley 
5453ba2698f1SMatthew G. Knepley   PetscFunctionBegin;
5454ba2698f1SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54554f572ea9SToby Isaac   PetscAssertPointer(celltype, 3);
54569f4ada15SMatthew G. Knepley   if (mesh->tr) {
54579f4ada15SMatthew G. Knepley     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
54589f4ada15SMatthew G. Knepley   } else {
545921027e53SStefano Zampini     PetscInt pStart, pEnd;
546021027e53SStefano Zampini 
546121027e53SStefano Zampini     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
546221027e53SStefano Zampini     if (!mesh->cellTypes) { /* XXX remove? optimize? */
546321027e53SStefano Zampini       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
546421027e53SStefano Zampini       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
546521027e53SStefano Zampini       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
546621027e53SStefano Zampini       for (PetscInt p = pStart; p < pEnd; p++) {
546721027e53SStefano Zampini         PetscCall(DMLabelGetValue(label, p, &ct));
546821027e53SStefano Zampini         mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
546921027e53SStefano Zampini       }
547021027e53SStefano Zampini     }
547121027e53SStefano Zampini     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
547221027e53SStefano Zampini     if (PetscDefined(USE_DEBUG)) {
54739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
54749566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, cell, &ct));
547563a3b9bcSJacob Faibussowitsch       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5476936381afSPierre Jolivet       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
547721027e53SStefano Zampini     }
54789f4ada15SMatthew G. Knepley   }
54793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5480ba2698f1SMatthew G. Knepley }
5481ba2698f1SMatthew G. Knepley 
5482412e9a14SMatthew G. Knepley /*@
5483412e9a14SMatthew G. Knepley   DMPlexSetCellType - Set the polytope type of a given cell
5484412e9a14SMatthew G. Knepley 
5485412e9a14SMatthew G. Knepley   Not Collective
5486412e9a14SMatthew G. Knepley 
5487412e9a14SMatthew G. Knepley   Input Parameters:
5488a1cb98faSBarry Smith + dm       - The `DMPLEX` object
5489412e9a14SMatthew G. Knepley . cell     - The cell
5490412e9a14SMatthew G. Knepley - celltype - The polytope type of the cell
5491412e9a14SMatthew G. Knepley 
5492a1cb98faSBarry Smith   Level: advanced
5493a1cb98faSBarry Smith 
5494a1cb98faSBarry Smith   Note:
5495a1cb98faSBarry Smith   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5496412e9a14SMatthew G. Knepley   is executed. This function will override the computed type. However, if automatic classification will not succeed
5497412e9a14SMatthew G. Knepley   and a user wants to manually specify all types, the classification must be disabled by calling
5498db485b19SStefano Zampini   DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5499412e9a14SMatthew G. Knepley 
55001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5501412e9a14SMatthew G. Knepley @*/
5502d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5503d71ae5a4SJacob Faibussowitsch {
550421027e53SStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
5505412e9a14SMatthew G. Knepley   DMLabel  label;
550621027e53SStefano Zampini   PetscInt pStart, pEnd;
5507412e9a14SMatthew G. Knepley 
5508412e9a14SMatthew G. Knepley   PetscFunctionBegin;
5509412e9a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
551021027e53SStefano Zampini   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
55119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
55129566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cell, celltype));
551321027e53SStefano Zampini   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
551421027e53SStefano Zampini   mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
55153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5516412e9a14SMatthew G. Knepley }
5517412e9a14SMatthew G. Knepley 
5518d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5519d71ae5a4SJacob Faibussowitsch {
5520efe440bfSMatthew G. Knepley   PetscSection section, s;
5521efe440bfSMatthew G. Knepley   Mat          m;
55223e922f36SToby Isaac   PetscInt     maxHeight;
5523dd4c3f67SMatthew G. Knepley   const char  *prefix;
5524552f7358SJed Brown 
5525552f7358SJed Brown   PetscFunctionBegin;
55269566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, cdm));
5527dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5528dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5529dd4c3f67SMatthew G. Knepley   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
55309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
55319566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
55329566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
55339566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*cdm, section));
55349566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
55359566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
55369566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
55379566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
55389566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&s));
55399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&m));
55408f4c458bSMatthew G. Knepley 
55419566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(*cdm, 1));
55429566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(*cdm));
5543dd4c3f67SMatthew G. Knepley   (*cdm)->cloneOpts = PETSC_TRUE;
5544dd4c3f67SMatthew G. Knepley   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
55453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5546552f7358SJed Brown }
5547552f7358SJed Brown 
5548d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5549d71ae5a4SJacob Faibussowitsch {
55506858538eSMatthew G. Knepley   Vec coordsLocal, cellCoordsLocal;
55516858538eSMatthew G. Knepley   DM  coordsDM, cellCoordsDM;
5552f19dbd58SToby Isaac 
5553f19dbd58SToby Isaac   PetscFunctionBegin;
5554f19dbd58SToby Isaac   *field = NULL;
55559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
55569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
55576858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
55586858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5559f19dbd58SToby Isaac   if (coordsLocal && coordsDM) {
55606858538eSMatthew G. Knepley     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
55616858538eSMatthew G. Knepley     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5562f19dbd58SToby Isaac   }
55633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5564f19dbd58SToby Isaac }
5565f19dbd58SToby Isaac 
55667cd05799SMatthew G. Knepley /*@C
55677cd05799SMatthew G. Knepley   DMPlexGetConeSection - Return a section which describes the layout of cone data
55687cd05799SMatthew G. Knepley 
55697cd05799SMatthew G. Knepley   Not Collective
55707cd05799SMatthew G. Knepley 
55712fe279fdSBarry Smith   Input Parameter:
5572a1cb98faSBarry Smith . dm - The `DMPLEX` object
55737cd05799SMatthew G. Knepley 
55747cd05799SMatthew G. Knepley   Output Parameter:
5575a1cb98faSBarry Smith . section - The `PetscSection` object
55767cd05799SMatthew G. Knepley 
55777cd05799SMatthew G. Knepley   Level: developer
55787cd05799SMatthew G. Knepley 
55791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
55807cd05799SMatthew G. Knepley @*/
5581d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5582d71ae5a4SJacob Faibussowitsch {
5583552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5584552f7358SJed Brown 
5585552f7358SJed Brown   PetscFunctionBegin;
5586552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5587552f7358SJed Brown   if (section) *section = mesh->coneSection;
55883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5589552f7358SJed Brown }
5590552f7358SJed Brown 
55917cd05799SMatthew G. Knepley /*@C
55927cd05799SMatthew G. Knepley   DMPlexGetSupportSection - Return a section which describes the layout of support data
55937cd05799SMatthew G. Knepley 
55947cd05799SMatthew G. Knepley   Not Collective
55957cd05799SMatthew G. Knepley 
55962fe279fdSBarry Smith   Input Parameter:
5597a1cb98faSBarry Smith . dm - The `DMPLEX` object
55987cd05799SMatthew G. Knepley 
55997cd05799SMatthew G. Knepley   Output Parameter:
5600a1cb98faSBarry Smith . section - The `PetscSection` object
56017cd05799SMatthew G. Knepley 
56027cd05799SMatthew G. Knepley   Level: developer
56037cd05799SMatthew G. Knepley 
56041cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
56057cd05799SMatthew G. Knepley @*/
5606d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5607d71ae5a4SJacob Faibussowitsch {
56088cb4d582SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
56098cb4d582SMatthew G. Knepley 
56108cb4d582SMatthew G. Knepley   PetscFunctionBegin;
56118cb4d582SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56128cb4d582SMatthew G. Knepley   if (section) *section = mesh->supportSection;
56133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56148cb4d582SMatthew G. Knepley }
56158cb4d582SMatthew G. Knepley 
56167cd05799SMatthew G. Knepley /*@C
56177cd05799SMatthew G. Knepley   DMPlexGetCones - Return cone data
56187cd05799SMatthew G. Knepley 
56197cd05799SMatthew G. Knepley   Not Collective
56207cd05799SMatthew G. Knepley 
56212fe279fdSBarry Smith   Input Parameter:
5622a1cb98faSBarry Smith . dm - The `DMPLEX` object
56237cd05799SMatthew G. Knepley 
56247cd05799SMatthew G. Knepley   Output Parameter:
56257cd05799SMatthew G. Knepley . cones - The cone for each point
56267cd05799SMatthew G. Knepley 
56277cd05799SMatthew G. Knepley   Level: developer
56287cd05799SMatthew G. Knepley 
56291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
56307cd05799SMatthew G. Knepley @*/
5631d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5632d71ae5a4SJacob Faibussowitsch {
5633552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5634552f7358SJed Brown 
5635552f7358SJed Brown   PetscFunctionBegin;
5636552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5637552f7358SJed Brown   if (cones) *cones = mesh->cones;
56383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5639552f7358SJed Brown }
5640552f7358SJed Brown 
56417cd05799SMatthew G. Knepley /*@C
56427cd05799SMatthew G. Knepley   DMPlexGetConeOrientations - Return cone orientation data
56437cd05799SMatthew G. Knepley 
56447cd05799SMatthew G. Knepley   Not Collective
56457cd05799SMatthew G. Knepley 
56462fe279fdSBarry Smith   Input Parameter:
5647a1cb98faSBarry Smith . dm - The `DMPLEX` object
56487cd05799SMatthew G. Knepley 
56497cd05799SMatthew G. Knepley   Output Parameter:
5650b5a892a1SMatthew G. Knepley . coneOrientations - The array of cone orientations for all points
56517cd05799SMatthew G. Knepley 
56527cd05799SMatthew G. Knepley   Level: developer
56537cd05799SMatthew G. Knepley 
5654b5a892a1SMatthew G. Knepley   Notes:
5655a1cb98faSBarry Smith   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`.
5656b5a892a1SMatthew G. Knepley 
5657a1cb98faSBarry Smith   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5658b5a892a1SMatthew G. Knepley 
56591cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
56607cd05799SMatthew G. Knepley @*/
5661d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5662d71ae5a4SJacob Faibussowitsch {
5663552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
5664552f7358SJed Brown 
5665552f7358SJed Brown   PetscFunctionBegin;
5666552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5667552f7358SJed Brown   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
56683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5669552f7358SJed Brown }
5670552f7358SJed Brown 
5671552f7358SJed Brown /******************************** FEM Support **********************************/
5672552f7358SJed Brown 
5673d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5674d2b2dc1eSMatthew G. Knepley {
5675d2b2dc1eSMatthew G. Knepley   PetscInt depth;
5676d2b2dc1eSMatthew G. Knepley 
5677d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
5678d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
5679d2b2dc1eSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5680d2b2dc1eSMatthew G. Knepley   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5681d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
5682d2b2dc1eSMatthew G. Knepley }
5683d2b2dc1eSMatthew G. Knepley 
56845962854dSMatthew G. Knepley PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS)
56855962854dSMatthew G. Knepley {
56865962854dSMatthew G. Knepley   PetscInt depth;
56875962854dSMatthew G. Knepley 
56885962854dSMatthew G. Knepley   PetscFunctionBegin;
56895962854dSMatthew G. Knepley   PetscCall(DMPlexGetDepth(plex, &depth));
56905962854dSMatthew G. Knepley   PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS));
56915962854dSMatthew G. Knepley   if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS));
56925962854dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
56935962854dSMatthew G. Knepley }
56945962854dSMatthew G. Knepley 
56959e8305c2SJed Brown /*
56969e8305c2SJed Brown  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
56979e8305c2SJed Brown  representing a line in the section.
56989e8305c2SJed Brown */
56995f82726aSMatthew G. Knepley static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor)
5700d71ae5a4SJacob Faibussowitsch {
5701e327e467SRezgar Shakeri   PetscObject  obj;
5702e327e467SRezgar Shakeri   PetscClassId id;
5703e327e467SRezgar Shakeri   PetscFE      fe = NULL;
5704e327e467SRezgar Shakeri 
57059e8305c2SJed Brown   PetscFunctionBeginHot;
57069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5707e327e467SRezgar Shakeri   PetscCall(DMGetField(dm, field, NULL, &obj));
5708e327e467SRezgar Shakeri   PetscCall(PetscObjectGetClassId(obj, &id));
5709e327e467SRezgar Shakeri   if (id == PETSCFE_CLASSID) fe = (PetscFE)obj;
5710e327e467SRezgar Shakeri 
5711e327e467SRezgar Shakeri   if (!fe) {
5712e327e467SRezgar Shakeri     /* Assume the full interpolated mesh is in the chart; lines in particular */
57139e8305c2SJed Brown     /* An order k SEM disc has k-1 dofs on an edge */
57149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
57159e8305c2SJed Brown     *k = *k / *Nc + 1;
5716e327e467SRezgar Shakeri   } else {
5717e327e467SRezgar Shakeri     PetscInt       dual_space_size, dim;
57185f82726aSMatthew G. Knepley     PetscDualSpace dsp;
57195f82726aSMatthew G. Knepley 
5720e327e467SRezgar Shakeri     PetscCall(DMGetDimension(dm, &dim));
57215f82726aSMatthew G. Knepley     PetscCall(PetscFEGetDualSpace(fe, &dsp));
57225f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size));
5723e327e467SRezgar Shakeri     *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1;
57245f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous));
57255f82726aSMatthew G. Knepley     PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor));
57265f82726aSMatthew G. Knepley   }
57275f82726aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
57285f82726aSMatthew G. Knepley }
57295f82726aSMatthew G. Knepley 
57305f82726aSMatthew G. Knepley static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof)
57315f82726aSMatthew G. Knepley {
57325f82726aSMatthew G. Knepley   PetscFunctionBeginHot;
57335f82726aSMatthew G. Knepley   if (tensor) {
57345f82726aSMatthew G. Knepley     *dof = PetscPowInt(k + 1, dim);
57355f82726aSMatthew G. Knepley   } else {
57365f82726aSMatthew G. Knepley     switch (dim) {
57375f82726aSMatthew G. Knepley     case 1:
57385f82726aSMatthew G. Knepley       *dof = k + 1;
57395f82726aSMatthew G. Knepley       break;
57405f82726aSMatthew G. Knepley     case 2:
57415f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2)) / 2;
57425f82726aSMatthew G. Knepley       break;
57435f82726aSMatthew G. Knepley     case 3:
57445f82726aSMatthew G. Knepley       *dof = ((k + 1) * (k + 2) * (k + 3)) / 6;
57455f82726aSMatthew G. Knepley       break;
57465f82726aSMatthew G. Knepley     default:
57475f82726aSMatthew G. Knepley       *dof = 0;
57485f82726aSMatthew G. Knepley     }
57499e8305c2SJed Brown   }
57503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57519e8305c2SJed Brown }
57529e8305c2SJed Brown 
5753a4355906SMatthew Knepley /*@
5754bc1eb3faSJed Brown 
5755bc1eb3faSJed Brown   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5756bc1eb3faSJed Brown   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
575720f4b53cSBarry Smith   section provided (or the section of the `DM`).
5758a4355906SMatthew Knepley 
5759a4355906SMatthew Knepley   Input Parameters:
576020f4b53cSBarry Smith + dm      - The `DM`
576120f4b53cSBarry Smith . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
576220f4b53cSBarry Smith - section - The `PetscSection` to reorder, or `NULL` for the default section
5763a4355906SMatthew Knepley 
5764bc1eb3faSJed Brown   Example:
5765bc1eb3faSJed Brown   A typical interpolated single-quad mesh might order points as
5766bc1eb3faSJed Brown .vb
5767bc1eb3faSJed Brown   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5768bc1eb3faSJed Brown 
5769bc1eb3faSJed Brown   v4 -- e6 -- v3
5770bc1eb3faSJed Brown   |           |
5771bc1eb3faSJed Brown   e7    c0    e8
5772bc1eb3faSJed Brown   |           |
5773bc1eb3faSJed Brown   v1 -- e5 -- v2
5774bc1eb3faSJed Brown .ve
5775bc1eb3faSJed Brown 
5776bc1eb3faSJed Brown   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5777bc1eb3faSJed Brown   dofs in the order of points, e.g.,
5778bc1eb3faSJed Brown .vb
5779bc1eb3faSJed Brown     c0 -> [0,1,2,3]
5780bc1eb3faSJed Brown     v1 -> [4]
5781bc1eb3faSJed Brown     ...
5782bc1eb3faSJed Brown     e5 -> [8, 9]
5783bc1eb3faSJed Brown .ve
5784bc1eb3faSJed Brown 
5785bc1eb3faSJed Brown   which corresponds to the dofs
5786bc1eb3faSJed Brown .vb
5787bc1eb3faSJed Brown     6   10  11  7
5788bc1eb3faSJed Brown     13  2   3   15
5789bc1eb3faSJed Brown     12  0   1   14
5790bc1eb3faSJed Brown     4   8   9   5
5791bc1eb3faSJed Brown .ve
5792bc1eb3faSJed Brown 
5793bc1eb3faSJed Brown   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5794bc1eb3faSJed Brown .vb
5795bc1eb3faSJed Brown   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5796bc1eb3faSJed Brown .ve
5797bc1eb3faSJed Brown 
5798bc1eb3faSJed Brown   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5799bc1eb3faSJed Brown .vb
5800bc1eb3faSJed Brown    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5801bc1eb3faSJed Brown .ve
5802bc1eb3faSJed Brown 
5803a4355906SMatthew Knepley   Level: developer
5804a4355906SMatthew Knepley 
5805da9ac489SAlbert Cowie   Notes:
5806a1cb98faSBarry Smith   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5807a1cb98faSBarry Smith   degree of the basis.
5808a1cb98faSBarry Smith 
5809da9ac489SAlbert Cowie   This is required to run with libCEED.
5810da9ac489SAlbert Cowie 
58111cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5812a4355906SMatthew Knepley @*/
5813d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5814d71ae5a4SJacob Faibussowitsch {
58157391a63aSMatthew G. Knepley   DMLabel   label;
5816bb197d40SJed Brown   PetscInt  dim, depth = -1, eStart = -1, Nf;
58175f82726aSMatthew G. Knepley   PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE;
58183194fc30SMatthew G. Knepley 
58193194fc30SMatthew G. Knepley   PetscFunctionBegin;
58209566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
58213ba16761SJacob Faibussowitsch   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5822a433471fSStefano Zampini   if (point < 0) {
5823a433471fSStefano Zampini     PetscInt sStart, sEnd;
5824a433471fSStefano Zampini 
58259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5826a433471fSStefano Zampini     point = sEnd - sStart ? sStart : point;
5827a433471fSStefano Zampini   }
58289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &label));
58299566063dSJacob Faibussowitsch   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
58309566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
58319371c9d4SSatish Balay   if (depth == 1) {
58329371c9d4SSatish Balay     eStart = point;
58339371c9d4SSatish Balay   } else if (depth == dim) {
58347391a63aSMatthew G. Knepley     const PetscInt *cone;
58357391a63aSMatthew G. Knepley 
58369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
5837d4e6627bSStefano Zampini     if (dim == 2) eStart = cone[0];
5838d4e6627bSStefano Zampini     else if (dim == 3) {
5839d4e6627bSStefano Zampini       const PetscInt *cone2;
58409566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5841d4e6627bSStefano Zampini       eStart = cone2[0];
584263a3b9bcSJacob 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);
584363a3b9bcSJacob 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);
5844e327e467SRezgar Shakeri 
58459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
5846bb197d40SJed Brown   for (PetscInt d = 1; d <= dim; d++) {
5847bb197d40SJed Brown     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5848bb197d40SJed Brown     PetscInt *perm;
5849bb197d40SJed Brown 
58503194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
58515f82726aSMatthew G. Knepley       PetscInt dof;
58525f82726aSMatthew G. Knepley 
58535f82726aSMatthew G. Knepley       PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
58545f82726aSMatthew G. Knepley       PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f);
58555f82726aSMatthew G. Knepley       if (!continuous && d < dim) continue;
58565f82726aSMatthew G. Knepley       PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
58575f82726aSMatthew G. Knepley       size += dof * Nc;
58583194fc30SMatthew G. Knepley     }
58599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &perm));
58603194fc30SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5861bb197d40SJed Brown       switch (d) {
5862babf31e0SJed Brown       case 1:
58635f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
58645f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
5865babf31e0SJed Brown         /*
5866babf31e0SJed Brown          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5867babf31e0SJed Brown          We want              [ vtx0; edge of length k-1; vtx1 ]
5868babf31e0SJed Brown          */
5869e327e467SRezgar Shakeri         if (continuous) {
5870babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
58719371c9d4SSatish Balay           for (i = 0; i < k - 1; i++)
58729371c9d4SSatish Balay             for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5873babf31e0SJed Brown           for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5874babf31e0SJed Brown           foffset = offset;
5875e327e467SRezgar Shakeri         } else {
58765f82726aSMatthew G. Knepley           PetscInt dof;
58775f82726aSMatthew G. Knepley 
58785f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
58795f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
58805f82726aSMatthew G. Knepley           foffset = offset;
5881e327e467SRezgar Shakeri         }
5882babf31e0SJed Brown         break;
588389eabcffSMatthew G. Knepley       case 2:
58843194fc30SMatthew 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} */
58855f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
58865f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
58873194fc30SMatthew G. Knepley         /* The SEM order is
58883194fc30SMatthew G. Knepley 
58893194fc30SMatthew G. Knepley          v_lb, {e_b}, v_rb,
589089eabcffSMatthew G. Knepley          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
58913194fc30SMatthew G. Knepley          v_lt, reverse {e_t}, v_rt
58923194fc30SMatthew G. Knepley          */
5893e327e467SRezgar Shakeri         if (continuous) {
58943194fc30SMatthew G. Knepley           const PetscInt of   = 0;
58953194fc30SMatthew G. Knepley           const PetscInt oeb  = of + PetscSqr(k - 1);
58963194fc30SMatthew G. Knepley           const PetscInt oer  = oeb + (k - 1);
58973194fc30SMatthew G. Knepley           const PetscInt oet  = oer + (k - 1);
58983194fc30SMatthew G. Knepley           const PetscInt oel  = oet + (k - 1);
58993194fc30SMatthew G. Knepley           const PetscInt ovlb = oel + (k - 1);
59003194fc30SMatthew G. Knepley           const PetscInt ovrb = ovlb + 1;
59013194fc30SMatthew G. Knepley           const PetscInt ovrt = ovrb + 1;
59023194fc30SMatthew G. Knepley           const PetscInt ovlt = ovrt + 1;
59033194fc30SMatthew G. Knepley           PetscInt       o;
59043194fc30SMatthew G. Knepley 
59053194fc30SMatthew G. Knepley           /* bottom */
59063194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
59079371c9d4SSatish Balay           for (o = oeb; o < oer; ++o)
59089371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
59093194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
59103194fc30SMatthew G. Knepley           /* middle */
59113194fc30SMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
59123194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
59139371c9d4SSatish Balay             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
59149371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
59153194fc30SMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
59163194fc30SMatthew G. Knepley           }
59173194fc30SMatthew G. Knepley           /* top */
59183194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
59199371c9d4SSatish Balay           for (o = oel - 1; o >= oet; --o)
59209371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
59213194fc30SMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
59223194fc30SMatthew G. Knepley           foffset = offset;
5923e327e467SRezgar Shakeri         } else {
59245f82726aSMatthew G. Knepley           PetscInt dof;
59255f82726aSMatthew G. Knepley 
59265f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
59275f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
59285f82726aSMatthew G. Knepley           foffset = offset;
59293194fc30SMatthew G. Knepley         }
593089eabcffSMatthew G. Knepley         break;
593189eabcffSMatthew G. Knepley       case 3:
593289eabcffSMatthew G. Knepley         /* The original hex closure is
593389eabcffSMatthew G. Knepley 
593489eabcffSMatthew G. Knepley          {c,
593589eabcffSMatthew G. Knepley          f_b, f_t, f_f, f_b, f_r, f_l,
593689eabcffSMatthew 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,
593789eabcffSMatthew G. Knepley          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
593889eabcffSMatthew G. Knepley          */
59395f82726aSMatthew G. Knepley         PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor));
59405f82726aSMatthew G. Knepley         if (!continuous && d < dim) continue;
594189eabcffSMatthew G. Knepley         /* The SEM order is
594289eabcffSMatthew G. Knepley          Bottom Slice
594389eabcffSMatthew G. Knepley          v_blf, {e^{(k-1)-n}_bf}, v_brf,
594489eabcffSMatthew G. Knepley          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
594589eabcffSMatthew G. Knepley          v_blb, {e_bb}, v_brb,
594689eabcffSMatthew G. Knepley 
594789eabcffSMatthew G. Knepley          Middle Slice (j)
594889eabcffSMatthew G. Knepley          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
594989eabcffSMatthew G. Knepley          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
595089eabcffSMatthew G. Knepley          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
595189eabcffSMatthew G. Knepley 
595289eabcffSMatthew G. Knepley          Top Slice
595389eabcffSMatthew G. Knepley          v_tlf, {e_tf}, v_trf,
595489eabcffSMatthew G. Knepley          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
595589eabcffSMatthew G. Knepley          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
595689eabcffSMatthew G. Knepley          */
5957e327e467SRezgar Shakeri         if (continuous) {
595889eabcffSMatthew G. Knepley           const PetscInt oc    = 0;
595989eabcffSMatthew G. Knepley           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
596089eabcffSMatthew G. Knepley           const PetscInt oft   = ofb + PetscSqr(k - 1);
596189eabcffSMatthew G. Knepley           const PetscInt off   = oft + PetscSqr(k - 1);
596289eabcffSMatthew G. Knepley           const PetscInt ofk   = off + PetscSqr(k - 1);
596389eabcffSMatthew G. Knepley           const PetscInt ofr   = ofk + PetscSqr(k - 1);
596489eabcffSMatthew G. Knepley           const PetscInt ofl   = ofr + PetscSqr(k - 1);
596589eabcffSMatthew G. Knepley           const PetscInt oebl  = ofl + PetscSqr(k - 1);
596689eabcffSMatthew G. Knepley           const PetscInt oebb  = oebl + (k - 1);
596789eabcffSMatthew G. Knepley           const PetscInt oebr  = oebb + (k - 1);
596889eabcffSMatthew G. Knepley           const PetscInt oebf  = oebr + (k - 1);
596989eabcffSMatthew G. Knepley           const PetscInt oetf  = oebf + (k - 1);
597089eabcffSMatthew G. Knepley           const PetscInt oetr  = oetf + (k - 1);
597189eabcffSMatthew G. Knepley           const PetscInt oetb  = oetr + (k - 1);
597289eabcffSMatthew G. Knepley           const PetscInt oetl  = oetb + (k - 1);
597389eabcffSMatthew G. Knepley           const PetscInt oerf  = oetl + (k - 1);
597489eabcffSMatthew G. Knepley           const PetscInt oelf  = oerf + (k - 1);
597589eabcffSMatthew G. Knepley           const PetscInt oelb  = oelf + (k - 1);
597689eabcffSMatthew G. Knepley           const PetscInt oerb  = oelb + (k - 1);
597789eabcffSMatthew G. Knepley           const PetscInt ovblf = oerb + (k - 1);
597889eabcffSMatthew G. Knepley           const PetscInt ovblb = ovblf + 1;
597989eabcffSMatthew G. Knepley           const PetscInt ovbrb = ovblb + 1;
598089eabcffSMatthew G. Knepley           const PetscInt ovbrf = ovbrb + 1;
598189eabcffSMatthew G. Knepley           const PetscInt ovtlf = ovbrf + 1;
598289eabcffSMatthew G. Knepley           const PetscInt ovtrf = ovtlf + 1;
598389eabcffSMatthew G. Knepley           const PetscInt ovtrb = ovtrf + 1;
598489eabcffSMatthew G. Knepley           const PetscInt ovtlb = ovtrb + 1;
598589eabcffSMatthew G. Knepley           PetscInt       o, n;
598689eabcffSMatthew G. Knepley 
598789eabcffSMatthew G. Knepley           /* Bottom Slice */
598889eabcffSMatthew G. Knepley           /*   bottom */
598989eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
59909371c9d4SSatish Balay           for (o = oetf - 1; o >= oebf; --o)
59919371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
599289eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
599389eabcffSMatthew G. Knepley           /*   middle */
599489eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
599589eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
59969371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n) {
59979371c9d4SSatish Balay               o = ofb + n * (k - 1) + i;
59989371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
59999371c9d4SSatish Balay             }
600089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
60013194fc30SMatthew G. Knepley           }
600289eabcffSMatthew G. Knepley           /*   top */
600389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
60049371c9d4SSatish Balay           for (o = oebb; o < oebr; ++o)
60059371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
600689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
600789eabcffSMatthew G. Knepley 
600889eabcffSMatthew G. Knepley           /* Middle Slice */
600989eabcffSMatthew G. Knepley           for (j = 0; j < k - 1; ++j) {
601089eabcffSMatthew G. Knepley             /*   bottom */
601189eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
60129371c9d4SSatish Balay             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
60139371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
601489eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
601589eabcffSMatthew G. Knepley             /*   middle */
601689eabcffSMatthew G. Knepley             for (i = 0; i < k - 1; ++i) {
601789eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
60189371c9d4SSatish Balay               for (n = 0; n < k - 1; ++n)
60199371c9d4SSatish Balay                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
602089eabcffSMatthew G. Knepley               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
602189eabcffSMatthew G. Knepley             }
602289eabcffSMatthew G. Knepley             /*   top */
602389eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
60249371c9d4SSatish Balay             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
60259371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
602689eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
602789eabcffSMatthew G. Knepley           }
602889eabcffSMatthew G. Knepley 
602989eabcffSMatthew G. Knepley           /* Top Slice */
603089eabcffSMatthew G. Knepley           /*   bottom */
603189eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
60329371c9d4SSatish Balay           for (o = oetf; o < oetr; ++o)
60339371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
603489eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
603589eabcffSMatthew G. Knepley           /*   middle */
603689eabcffSMatthew G. Knepley           for (i = 0; i < k - 1; ++i) {
603789eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
60389371c9d4SSatish Balay             for (n = 0; n < k - 1; ++n)
60399371c9d4SSatish Balay               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
604089eabcffSMatthew G. Knepley             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
604189eabcffSMatthew G. Knepley           }
604289eabcffSMatthew G. Knepley           /*   top */
604389eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
60449371c9d4SSatish Balay           for (o = oetl - 1; o >= oetb; --o)
60459371c9d4SSatish Balay             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
604689eabcffSMatthew G. Knepley           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
604789eabcffSMatthew G. Knepley 
604889eabcffSMatthew G. Knepley           foffset = offset;
6049e327e467SRezgar Shakeri         } else {
60505f82726aSMatthew G. Knepley           PetscInt dof;
60515f82726aSMatthew G. Knepley 
60525f82726aSMatthew G. Knepley           PetscCall(GetFieldSize_Private(d, k, tensor, &dof));
60535f82726aSMatthew G. Knepley           for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset;
60545f82726aSMatthew G. Knepley           foffset = offset;
605589eabcffSMatthew G. Knepley         }
605689eabcffSMatthew G. Knepley         break;
6057d71ae5a4SJacob Faibussowitsch       default:
6058d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
605989eabcffSMatthew G. Knepley       }
606089eabcffSMatthew G. Knepley     }
606163a3b9bcSJacob Faibussowitsch     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
60623194fc30SMatthew G. Knepley     /* Check permutation */
60633194fc30SMatthew G. Knepley     {
60643194fc30SMatthew G. Knepley       PetscInt *check;
60653194fc30SMatthew G. Knepley 
60669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &check));
60671dca8a05SBarry Smith       for (i = 0; i < size; ++i) {
60681dca8a05SBarry Smith         check[i] = -1;
60691dca8a05SBarry 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]);
60701dca8a05SBarry Smith       }
60713194fc30SMatthew G. Knepley       for (i = 0; i < size; ++i) check[perm[i]] = i;
60721dca8a05SBarry Smith       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
60739566063dSJacob Faibussowitsch       PetscCall(PetscFree(check));
60743194fc30SMatthew G. Knepley     }
60759566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
6076a05c9aa3SJed Brown     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
6077a05c9aa3SJed Brown       PetscInt *loc_perm;
60789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size * 2, &loc_perm));
6079a05c9aa3SJed Brown       for (PetscInt i = 0; i < size; i++) {
6080a05c9aa3SJed Brown         loc_perm[i]        = perm[i];
6081a05c9aa3SJed Brown         loc_perm[size + i] = size + perm[i];
6082a05c9aa3SJed Brown       }
60839566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
6084a05c9aa3SJed Brown     }
6085bb197d40SJed Brown   }
60863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60873194fc30SMatthew G. Knepley }
60883194fc30SMatthew G. Knepley 
6089d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
6090d71ae5a4SJacob Faibussowitsch {
6091e071409bSToby Isaac   PetscDS  prob;
6092e071409bSToby Isaac   PetscInt depth, Nf, h;
6093e071409bSToby Isaac   DMLabel  label;
6094e071409bSToby Isaac 
6095e071409bSToby Isaac   PetscFunctionBeginHot;
60969566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
6097e071409bSToby Isaac   Nf      = prob->Nf;
6098e071409bSToby Isaac   label   = dm->depthLabel;
6099e071409bSToby Isaac   *dspace = NULL;
6100e071409bSToby Isaac   if (field < Nf) {
6101e071409bSToby Isaac     PetscObject disc = prob->disc[field];
6102e071409bSToby Isaac 
6103e071409bSToby Isaac     if (disc->classid == PETSCFE_CLASSID) {
6104e071409bSToby Isaac       PetscDualSpace dsp;
6105e071409bSToby Isaac 
61069566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
61079566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(label, &depth));
61089566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(label, point, &h));
6109e071409bSToby Isaac       h = depth - 1 - h;
6110e071409bSToby Isaac       if (h) {
61119566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
6112e071409bSToby Isaac       } else {
6113e071409bSToby Isaac         *dspace = dsp;
6114e071409bSToby Isaac       }
6115e071409bSToby Isaac     }
6116e071409bSToby Isaac   }
61173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6118e071409bSToby Isaac }
6119e071409bSToby Isaac 
6120d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6121d71ae5a4SJacob Faibussowitsch {
612228351e22SJed Brown   PetscScalar       *array;
612328351e22SJed Brown   const PetscScalar *vArray;
6124d9917b9dSMatthew G. Knepley   const PetscInt    *cone, *coneO;
61251a271a75SMatthew G. Knepley   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;
6126552f7358SJed Brown 
61271b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
61289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
61299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
61309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
61319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
61323f7cbbe7SMatthew G. Knepley   if (!values || !*values) {
61339df71ca4SMatthew G. Knepley     if ((point >= pStart) && (point < pEnd)) {
61349df71ca4SMatthew G. Knepley       PetscInt dof;
6135d9917b9dSMatthew G. Knepley 
61369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, point, &dof));
61379df71ca4SMatthew G. Knepley       size += dof;
61389df71ca4SMatthew G. Knepley     }
61399df71ca4SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
61409df71ca4SMatthew G. Knepley       const PetscInt cp = cone[p];
61412a3aaacfSMatthew G. Knepley       PetscInt       dof;
61425a1bb5cfSMatthew G. Knepley 
61435a1bb5cfSMatthew G. Knepley       if ((cp < pStart) || (cp >= pEnd)) continue;
61449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, cp, &dof));
61455a1bb5cfSMatthew G. Knepley       size += dof;
61465a1bb5cfSMatthew G. Knepley     }
61473f7cbbe7SMatthew G. Knepley     if (!values) {
61483f7cbbe7SMatthew G. Knepley       if (csize) *csize = size;
61493ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
61503f7cbbe7SMatthew G. Knepley     }
61519566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
6152982e9ed1SMatthew G. Knepley   } else {
6153982e9ed1SMatthew G. Knepley     array = *values;
6154982e9ed1SMatthew G. Knepley   }
61559df71ca4SMatthew G. Knepley   size = 0;
615628351e22SJed Brown   PetscCall(VecGetArrayRead(v, &vArray));
61579df71ca4SMatthew G. Knepley   if ((point >= pStart) && (point < pEnd)) {
61589df71ca4SMatthew G. Knepley     PetscInt           dof, off, d;
615928351e22SJed Brown     const PetscScalar *varr;
6160d9917b9dSMatthew G. Knepley 
61619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
61629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
61638e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
6164ad540459SPierre Jolivet     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
61659df71ca4SMatthew G. Knepley     size += dof;
61669df71ca4SMatthew G. Knepley   }
61679df71ca4SMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
61689df71ca4SMatthew G. Knepley     const PetscInt     cp = cone[p];
61699df71ca4SMatthew G. Knepley     PetscInt           o  = coneO[p];
61705a1bb5cfSMatthew G. Knepley     PetscInt           dof, off, d;
617128351e22SJed Brown     const PetscScalar *varr;
61725a1bb5cfSMatthew G. Knepley 
617352ed52e8SMatthew G. Knepley     if ((cp < pStart) || (cp >= pEnd)) continue;
61749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
61759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, cp, &off));
61768e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
61775a1bb5cfSMatthew G. Knepley     if (o >= 0) {
6178ad540459SPierre Jolivet       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
61795a1bb5cfSMatthew G. Knepley     } else {
6180ad540459SPierre Jolivet       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
61815a1bb5cfSMatthew G. Knepley     }
61829df71ca4SMatthew G. Knepley     size += dof;
61835a1bb5cfSMatthew G. Knepley   }
618428351e22SJed Brown   PetscCall(VecRestoreArrayRead(v, &vArray));
61859df71ca4SMatthew G. Knepley   if (!*values) {
61865a1bb5cfSMatthew G. Knepley     if (csize) *csize = size;
61875a1bb5cfSMatthew G. Knepley     *values = array;
61889df71ca4SMatthew G. Knepley   } else {
618963a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
61908c312ff3SMatthew G. Knepley     *csize = size;
61919df71ca4SMatthew G. Knepley   }
61923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61935a1bb5cfSMatthew G. Knepley }
6194d9917b9dSMatthew G. Knepley 
619527f02ce8SMatthew G. Knepley /* Compress out points not in the section */
6196d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
6197d71ae5a4SJacob Faibussowitsch {
619827f02ce8SMatthew G. Knepley   const PetscInt np = *numPoints;
619927f02ce8SMatthew G. Knepley   PetscInt       pStart, pEnd, p, q;
620027f02ce8SMatthew G. Knepley 
62019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
620227f02ce8SMatthew G. Knepley   for (p = 0, q = 0; p < np; ++p) {
620327f02ce8SMatthew G. Knepley     const PetscInt r = points[p * 2];
620427f02ce8SMatthew G. Knepley     if ((r >= pStart) && (r < pEnd)) {
620527f02ce8SMatthew G. Knepley       points[q * 2]     = r;
620627f02ce8SMatthew G. Knepley       points[q * 2 + 1] = points[p * 2 + 1];
620727f02ce8SMatthew G. Knepley       ++q;
620827f02ce8SMatthew G. Knepley     }
620927f02ce8SMatthew G. Knepley   }
621027f02ce8SMatthew G. Knepley   *numPoints = q;
62113ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
621227f02ce8SMatthew G. Knepley }
621327f02ce8SMatthew G. Knepley 
621497529cf3SJed Brown /* Compressed closure does not apply closure permutation */
621507218a29SMatthew G. Knepley PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6216d71ae5a4SJacob Faibussowitsch {
621727f02ce8SMatthew G. Knepley   const PetscInt *cla = NULL;
6218923c78e0SToby Isaac   PetscInt        np, *pts = NULL;
6219923c78e0SToby Isaac 
6220923c78e0SToby Isaac   PetscFunctionBeginHot;
62219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
622207218a29SMatthew G. Knepley   if (!ornt && *clPoints) {
6223923c78e0SToby Isaac     PetscInt dof, off;
6224923c78e0SToby Isaac 
62259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
62269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
62279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(*clPoints, &cla));
6228923c78e0SToby Isaac     np  = dof / 2;
62298e3a54c0SPierre Jolivet     pts = PetscSafePointerPlusOffset((PetscInt *)cla, off);
623027f02ce8SMatthew G. Knepley   } else {
623107218a29SMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
62329566063dSJacob Faibussowitsch     PetscCall(CompressPoints_Private(section, &np, pts));
6233923c78e0SToby Isaac   }
6234923c78e0SToby Isaac   *numPoints = np;
6235923c78e0SToby Isaac   *points    = pts;
6236923c78e0SToby Isaac   *clp       = cla;
62373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6238923c78e0SToby Isaac }
6239923c78e0SToby Isaac 
6240d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
6241d71ae5a4SJacob Faibussowitsch {
6242923c78e0SToby Isaac   PetscFunctionBeginHot;
6243923c78e0SToby Isaac   if (!*clPoints) {
62449566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
6245923c78e0SToby Isaac   } else {
62469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(*clPoints, clp));
6247923c78e0SToby Isaac   }
6248923c78e0SToby Isaac   *numPoints = 0;
6249923c78e0SToby Isaac   *points    = NULL;
6250923c78e0SToby Isaac   *clSec     = NULL;
6251923c78e0SToby Isaac   *clPoints  = NULL;
6252923c78e0SToby Isaac   *clp       = NULL;
62533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6254923c78e0SToby Isaac }
6255923c78e0SToby Isaac 
6256d71ae5a4SJacob 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[])
6257d71ae5a4SJacob Faibussowitsch {
62581a271a75SMatthew G. Knepley   PetscInt            offset = 0, p;
625997e99dd9SToby Isaac   const PetscInt    **perms  = NULL;
626097e99dd9SToby Isaac   const PetscScalar **flips  = NULL;
62611a271a75SMatthew G. Knepley 
62621a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6263fe02ba77SJed Brown   *size = 0;
62649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
626597e99dd9SToby Isaac   for (p = 0; p < numPoints; p++) {
626697e99dd9SToby Isaac     const PetscInt     point = points[2 * p];
626797e99dd9SToby Isaac     const PetscInt    *perm  = perms ? perms[p] : NULL;
626897e99dd9SToby Isaac     const PetscScalar *flip  = flips ? flips[p] : NULL;
62691a271a75SMatthew G. Knepley     PetscInt           dof, off, d;
62701a271a75SMatthew G. Knepley     const PetscScalar *varr;
62711a271a75SMatthew G. Knepley 
62729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, point, &dof));
62739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, point, &off));
62748e3a54c0SPierre Jolivet     varr = PetscSafePointerPlusOffset(vArray, off);
627597e99dd9SToby Isaac     if (clperm) {
627697e99dd9SToby Isaac       if (perm) {
627797e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
62781a271a75SMatthew G. Knepley       } else {
627997e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
628097e99dd9SToby Isaac       }
628197e99dd9SToby Isaac       if (flip) {
628297e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
628397e99dd9SToby Isaac       }
628497e99dd9SToby Isaac     } else {
628597e99dd9SToby Isaac       if (perm) {
628697e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
628797e99dd9SToby Isaac       } else {
628897e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
628997e99dd9SToby Isaac       }
629097e99dd9SToby Isaac       if (flip) {
629197e99dd9SToby Isaac         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
62921a271a75SMatthew G. Knepley       }
62931a271a75SMatthew G. Knepley     }
629497e99dd9SToby Isaac     offset += dof;
629597e99dd9SToby Isaac   }
62969566063dSJacob Faibussowitsch   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
62971a271a75SMatthew G. Knepley   *size = offset;
62983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62991a271a75SMatthew G. Knepley }
63001a271a75SMatthew G. Knepley 
6301d71ae5a4SJacob 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[])
6302d71ae5a4SJacob Faibussowitsch {
63031a271a75SMatthew G. Knepley   PetscInt offset = 0, f;
63041a271a75SMatthew G. Knepley 
63051a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
6306fe02ba77SJed Brown   *size = 0;
63071a271a75SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
630897e99dd9SToby Isaac     PetscInt            p;
630997e99dd9SToby Isaac     const PetscInt    **perms = NULL;
631097e99dd9SToby Isaac     const PetscScalar **flips = NULL;
63111a271a75SMatthew G. Knepley 
63129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
631397e99dd9SToby Isaac     for (p = 0; p < numPoints; p++) {
631497e99dd9SToby Isaac       const PetscInt     point = points[2 * p];
631597e99dd9SToby Isaac       PetscInt           fdof, foff, b;
63161a271a75SMatthew G. Knepley       const PetscScalar *varr;
631797e99dd9SToby Isaac       const PetscInt    *perm = perms ? perms[p] : NULL;
631897e99dd9SToby Isaac       const PetscScalar *flip = flips ? flips[p] : NULL;
63191a271a75SMatthew G. Knepley 
63209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
63219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
63221a271a75SMatthew G. Knepley       varr = &vArray[foff];
632397e99dd9SToby Isaac       if (clperm) {
63249371c9d4SSatish Balay         if (perm) {
6325ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
63261a271a75SMatthew G. Knepley         } else {
6327ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
63289371c9d4SSatish Balay         }
63299371c9d4SSatish Balay         if (flip) {
6330ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
63319371c9d4SSatish Balay         }
63329371c9d4SSatish Balay       } else {
63339371c9d4SSatish Balay         if (perm) {
6334ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
63359371c9d4SSatish Balay         } else {
6336ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
63379371c9d4SSatish Balay         }
63389371c9d4SSatish Balay         if (flip) {
6339ad540459SPierre Jolivet           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
63409371c9d4SSatish Balay         }
63411a271a75SMatthew G. Knepley       }
634297e99dd9SToby Isaac       offset += fdof;
63431a271a75SMatthew G. Knepley     }
63449566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
63451a271a75SMatthew G. Knepley   }
63461a271a75SMatthew G. Knepley   *size = offset;
63473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63481a271a75SMatthew G. Knepley }
63491a271a75SMatthew G. Knepley 
6350e8e188d2SZach Atkins PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
635107218a29SMatthew G. Knepley {
635207218a29SMatthew G. Knepley   PetscSection    clSection;
635307218a29SMatthew G. Knepley   IS              clPoints;
635407218a29SMatthew G. Knepley   PetscInt       *points = NULL;
6355e8e188d2SZach Atkins   const PetscInt *clp, *perm = NULL;
635607218a29SMatthew G. Knepley   PetscInt        depth, numFields, numPoints, asize;
635707218a29SMatthew G. Knepley 
635807218a29SMatthew G. Knepley   PetscFunctionBeginHot;
635907218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
636007218a29SMatthew G. Knepley   if (!section) PetscCall(DMGetLocalSection(dm, &section));
636107218a29SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6362e8e188d2SZach Atkins   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
636307218a29SMatthew G. Knepley   PetscCall(DMPlexGetDepth(dm, &depth));
636407218a29SMatthew G. Knepley   PetscCall(PetscSectionGetNumFields(section, &numFields));
636507218a29SMatthew G. Knepley   if (depth == 1 && numFields < 2) {
636607218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
636707218a29SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
636807218a29SMatthew G. Knepley   }
636907218a29SMatthew G. Knepley   /* Get points */
637007218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
637107218a29SMatthew G. Knepley   /* Get sizes */
637207218a29SMatthew G. Knepley   asize = 0;
637307218a29SMatthew G. Knepley   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
637407218a29SMatthew G. Knepley     PetscInt dof;
637507218a29SMatthew G. Knepley     PetscCall(PetscSectionGetDof(section, points[p], &dof));
637607218a29SMatthew G. Knepley     asize += dof;
637707218a29SMatthew G. Knepley   }
637807218a29SMatthew G. Knepley   if (values) {
637907218a29SMatthew G. Knepley     const PetscScalar *vArray;
638007218a29SMatthew G. Knepley     PetscInt           size;
638107218a29SMatthew G. Knepley 
638207218a29SMatthew G. Knepley     if (*values) {
638307218a29SMatthew 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);
638407218a29SMatthew G. Knepley     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6385e8e188d2SZach Atkins     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
638607218a29SMatthew G. Knepley     PetscCall(VecGetArrayRead(v, &vArray));
638707218a29SMatthew G. Knepley     /* Get values */
638807218a29SMatthew G. Knepley     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
638907218a29SMatthew G. Knepley     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
639007218a29SMatthew 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);
639107218a29SMatthew G. Knepley     /* Cleanup array */
639207218a29SMatthew G. Knepley     PetscCall(VecRestoreArrayRead(v, &vArray));
639307218a29SMatthew G. Knepley   }
639407218a29SMatthew G. Knepley   if (csize) *csize = asize;
639507218a29SMatthew G. Knepley   /* Cleanup points */
639607218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
639707218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
639807218a29SMatthew G. Knepley }
639907218a29SMatthew G. Knepley 
6400552f7358SJed Brown /*@C
6401552f7358SJed Brown   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6402552f7358SJed Brown 
6403552f7358SJed Brown   Not collective
6404552f7358SJed Brown 
6405552f7358SJed Brown   Input Parameters:
6406a1cb98faSBarry Smith + dm      - The `DM`
640720f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6408552f7358SJed Brown . v       - The local vector
6409a1cb98faSBarry Smith - point   - The point in the `DM`
6410552f7358SJed Brown 
64116b867d5aSJose E. Roman   Input/Output Parameters:
641220f4b53cSBarry Smith + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
641320f4b53cSBarry Smith - values - An array to use for the values, or `NULL` to have it allocated automatically;
641420f4b53cSBarry Smith            if the user provided `NULL`, it is a borrowed array and should not be freed
641522c1ee49SMatthew G. Knepley 
6416552f7358SJed Brown   Level: intermediate
6417552f7358SJed Brown 
6418a1cb98faSBarry Smith   Notes:
641920f4b53cSBarry Smith   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6420a1cb98faSBarry Smith   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6421a1cb98faSBarry Smith   assembly function, and a user may already have allocated storage for this operation.
6422a1cb98faSBarry Smith 
6423a1cb98faSBarry Smith   A typical use could be
6424a1cb98faSBarry Smith .vb
6425a1cb98faSBarry Smith    values = NULL;
6426a1cb98faSBarry Smith    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6427a1cb98faSBarry Smith    for (cl = 0; cl < clSize; ++cl) {
6428a1cb98faSBarry Smith      <Compute on closure>
6429a1cb98faSBarry Smith    }
6430a1cb98faSBarry Smith    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6431a1cb98faSBarry Smith .ve
6432a1cb98faSBarry Smith   or
6433a1cb98faSBarry Smith .vb
6434a1cb98faSBarry Smith    PetscMalloc1(clMaxSize, &values);
6435a1cb98faSBarry Smith    for (p = pStart; p < pEnd; ++p) {
6436a1cb98faSBarry Smith      clSize = clMaxSize;
6437a1cb98faSBarry Smith      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6438a1cb98faSBarry Smith      for (cl = 0; cl < clSize; ++cl) {
6439a1cb98faSBarry Smith        <Compute on closure>
6440a1cb98faSBarry Smith      }
6441a1cb98faSBarry Smith    }
6442a1cb98faSBarry Smith    PetscFree(values);
6443a1cb98faSBarry Smith .ve
6444a1cb98faSBarry Smith 
644560225df5SJacob Faibussowitsch   Fortran Notes:
644620f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6447a1cb98faSBarry Smith 
64481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6449552f7358SJed Brown @*/
6450d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6451d71ae5a4SJacob Faibussowitsch {
6452d9917b9dSMatthew G. Knepley   PetscFunctionBeginHot;
6453e8e188d2SZach Atkins   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
64543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6455552f7358SJed Brown }
6456552f7358SJed Brown 
6457d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6458d71ae5a4SJacob Faibussowitsch {
6459e5c487bfSMatthew G. Knepley   DMLabel            depthLabel;
6460e5c487bfSMatthew G. Knepley   PetscSection       clSection;
6461e5c487bfSMatthew G. Knepley   IS                 clPoints;
6462e5c487bfSMatthew G. Knepley   PetscScalar       *array;
6463e5c487bfSMatthew G. Knepley   const PetscScalar *vArray;
6464e5c487bfSMatthew G. Knepley   PetscInt          *points = NULL;
6465c459fbc1SJed Brown   const PetscInt    *clp, *perm = NULL;
6466c459fbc1SJed Brown   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6467e5c487bfSMatthew G. Knepley 
6468e5c487bfSMatthew G. Knepley   PetscFunctionBeginHot;
6469e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
64709566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6471e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6472e5c487bfSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
64739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &mdepth));
64749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
64759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
6476e5c487bfSMatthew G. Knepley   if (mdepth == 1 && numFields < 2) {
64779566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
64783ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6479e5c487bfSMatthew G. Knepley   }
6480e5c487bfSMatthew G. Knepley   /* Get points */
648107218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6482c459fbc1SJed Brown   for (clsize = 0, p = 0; p < Np; p++) {
6483c459fbc1SJed Brown     PetscInt dof;
64849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6485c459fbc1SJed Brown     clsize += dof;
6486c459fbc1SJed Brown   }
64879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6488e5c487bfSMatthew G. Knepley   /* Filter points */
6489e5c487bfSMatthew G. Knepley   for (p = 0; p < numPoints * 2; p += 2) {
6490e5c487bfSMatthew G. Knepley     PetscInt dep;
6491e5c487bfSMatthew G. Knepley 
64929566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6493e5c487bfSMatthew G. Knepley     if (dep != depth) continue;
6494e5c487bfSMatthew G. Knepley     points[Np * 2 + 0] = points[p];
6495e5c487bfSMatthew G. Knepley     points[Np * 2 + 1] = points[p + 1];
6496e5c487bfSMatthew G. Knepley     ++Np;
6497e5c487bfSMatthew G. Knepley   }
6498e5c487bfSMatthew G. Knepley   /* Get array */
6499e5c487bfSMatthew G. Knepley   if (!values || !*values) {
6500e5c487bfSMatthew G. Knepley     PetscInt asize = 0, dof;
6501e5c487bfSMatthew G. Knepley 
6502e5c487bfSMatthew G. Knepley     for (p = 0; p < Np * 2; p += 2) {
65039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6504e5c487bfSMatthew G. Knepley       asize += dof;
6505e5c487bfSMatthew G. Knepley     }
6506e5c487bfSMatthew G. Knepley     if (!values) {
65079566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6508e5c487bfSMatthew G. Knepley       if (csize) *csize = asize;
65093ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
6510e5c487bfSMatthew G. Knepley     }
65119566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6512e5c487bfSMatthew G. Knepley   } else {
6513e5c487bfSMatthew G. Knepley     array = *values;
6514e5c487bfSMatthew G. Knepley   }
65159566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &vArray));
6516e5c487bfSMatthew G. Knepley   /* Get values */
65179566063dSJacob Faibussowitsch   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
65189566063dSJacob Faibussowitsch   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6519e5c487bfSMatthew G. Knepley   /* Cleanup points */
65209566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6521e5c487bfSMatthew G. Knepley   /* Cleanup array */
65229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &vArray));
6523e5c487bfSMatthew G. Knepley   if (!*values) {
6524e5c487bfSMatthew G. Knepley     if (csize) *csize = size;
6525e5c487bfSMatthew G. Knepley     *values = array;
6526e5c487bfSMatthew G. Knepley   } else {
652763a3b9bcSJacob Faibussowitsch     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6528e5c487bfSMatthew G. Knepley     *csize = size;
6529e5c487bfSMatthew G. Knepley   }
65303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6531e5c487bfSMatthew G. Knepley }
6532e5c487bfSMatthew G. Knepley 
6533552f7358SJed Brown /*@C
6534552f7358SJed Brown   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6535552f7358SJed Brown 
6536552f7358SJed Brown   Not collective
6537552f7358SJed Brown 
6538552f7358SJed Brown   Input Parameters:
6539a1cb98faSBarry Smith + dm      - The `DM`
654020f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
6541552f7358SJed Brown . v       - The local vector
6542a1cb98faSBarry Smith . point   - The point in the `DM`
654320f4b53cSBarry Smith . csize   - The number of values in the closure, or `NULL`
6544552f7358SJed Brown - values  - The array of values, which is a borrowed array and should not be freed
6545552f7358SJed Brown 
6546552f7358SJed Brown   Level: intermediate
6547552f7358SJed Brown 
6548a1cb98faSBarry Smith   Note:
654920f4b53cSBarry Smith   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6550a1cb98faSBarry Smith 
655160225df5SJacob Faibussowitsch   Fortran Notes:
655220f4b53cSBarry Smith   The `csize` argument is not present in the Fortran binding since it is internal to the array.
6553a1cb98faSBarry Smith 
65541cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6555552f7358SJed Brown @*/
6556d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6557d71ae5a4SJacob Faibussowitsch {
6558552f7358SJed Brown   PetscInt size = 0;
6559552f7358SJed Brown 
6560552f7358SJed Brown   PetscFunctionBegin;
6561552f7358SJed Brown   /* Should work without recalculating size */
65629566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6563c9fdaa05SMatthew G. Knepley   *values = NULL;
65643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6565552f7358SJed Brown }
6566552f7358SJed Brown 
6567d71ae5a4SJacob Faibussowitsch static inline void add(PetscScalar *x, PetscScalar y)
6568d71ae5a4SJacob Faibussowitsch {
65699371c9d4SSatish Balay   *x += y;
65709371c9d4SSatish Balay }
6571d71ae5a4SJacob Faibussowitsch static inline void insert(PetscScalar *x, PetscScalar y)
6572d71ae5a4SJacob Faibussowitsch {
65739371c9d4SSatish Balay   *x = y;
65749371c9d4SSatish Balay }
6575552f7358SJed Brown 
6576d71ae5a4SJacob 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[])
6577d71ae5a4SJacob Faibussowitsch {
6578552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
6579552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6580552f7358SJed Brown   PetscScalar    *a;
6581552f7358SJed Brown   PetscInt        off, cind = 0, k;
6582552f7358SJed Brown 
6583552f7358SJed Brown   PetscFunctionBegin;
65849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
65859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6586552f7358SJed Brown   a = &array[off];
6587552f7358SJed Brown   if (!cdof || setBC) {
658897e99dd9SToby Isaac     if (clperm) {
65899371c9d4SSatish Balay       if (perm) {
6590ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6591552f7358SJed Brown       } else {
6592ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
65939371c9d4SSatish Balay       }
65949371c9d4SSatish Balay     } else {
65959371c9d4SSatish Balay       if (perm) {
6596ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
65979371c9d4SSatish Balay       } else {
6598ad540459SPierre Jolivet         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
65999371c9d4SSatish Balay       }
6600552f7358SJed Brown     }
6601552f7358SJed Brown   } else {
66029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
660397e99dd9SToby Isaac     if (clperm) {
66049371c9d4SSatish Balay       if (perm) {
66059371c9d4SSatish Balay         for (k = 0; k < dof; ++k) {
66069371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
66079371c9d4SSatish Balay             ++cind;
66089371c9d4SSatish Balay             continue;
66099371c9d4SSatish Balay           }
661097e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6611552f7358SJed Brown         }
6612552f7358SJed Brown       } else {
6613552f7358SJed Brown         for (k = 0; k < dof; ++k) {
66149371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
66159371c9d4SSatish Balay             ++cind;
66169371c9d4SSatish Balay             continue;
66179371c9d4SSatish Balay           }
661897e99dd9SToby Isaac           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
661997e99dd9SToby Isaac         }
662097e99dd9SToby Isaac       }
662197e99dd9SToby Isaac     } else {
662297e99dd9SToby Isaac       if (perm) {
662397e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
66249371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
66259371c9d4SSatish Balay             ++cind;
66269371c9d4SSatish Balay             continue;
66279371c9d4SSatish Balay           }
662897e99dd9SToby Isaac           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
662997e99dd9SToby Isaac         }
663097e99dd9SToby Isaac       } else {
663197e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
66329371c9d4SSatish Balay           if ((cind < cdof) && (k == cdofs[cind])) {
66339371c9d4SSatish Balay             ++cind;
66349371c9d4SSatish Balay             continue;
66359371c9d4SSatish Balay           }
663697e99dd9SToby Isaac           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
663797e99dd9SToby Isaac         }
6638552f7358SJed Brown       }
6639552f7358SJed Brown     }
6640552f7358SJed Brown   }
66413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6642552f7358SJed Brown }
6643552f7358SJed Brown 
6644d71ae5a4SJacob 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[])
6645d71ae5a4SJacob Faibussowitsch {
6646a5e93ea8SMatthew G. Knepley   PetscInt        cdof;  /* The number of constraints on this point */
6647a5e93ea8SMatthew G. Knepley   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6648a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
6649a5e93ea8SMatthew G. Knepley   PetscInt        off, cind = 0, k;
6650a5e93ea8SMatthew G. Knepley 
6651a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
66529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
66539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(section, point, &off));
6654a5e93ea8SMatthew G. Knepley   a = &array[off];
6655a5e93ea8SMatthew G. Knepley   if (cdof) {
66569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
665797e99dd9SToby Isaac     if (clperm) {
665897e99dd9SToby Isaac       if (perm) {
6659a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6660a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
666197e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
666297e99dd9SToby Isaac             cind++;
6663a5e93ea8SMatthew G. Knepley           }
6664a5e93ea8SMatthew G. Knepley         }
6665a5e93ea8SMatthew G. Knepley       } else {
6666a5e93ea8SMatthew G. Knepley         for (k = 0; k < dof; ++k) {
6667a5e93ea8SMatthew G. Knepley           if ((cind < cdof) && (k == cdofs[cind])) {
666897e99dd9SToby Isaac             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
666997e99dd9SToby Isaac             cind++;
667097e99dd9SToby Isaac           }
667197e99dd9SToby Isaac         }
667297e99dd9SToby Isaac       }
667397e99dd9SToby Isaac     } else {
667497e99dd9SToby Isaac       if (perm) {
667597e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
667697e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
667797e99dd9SToby Isaac             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
667897e99dd9SToby Isaac             cind++;
667997e99dd9SToby Isaac           }
668097e99dd9SToby Isaac         }
668197e99dd9SToby Isaac       } else {
668297e99dd9SToby Isaac         for (k = 0; k < dof; ++k) {
668397e99dd9SToby Isaac           if ((cind < cdof) && (k == cdofs[cind])) {
668497e99dd9SToby Isaac             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
668597e99dd9SToby Isaac             cind++;
668697e99dd9SToby Isaac           }
6687a5e93ea8SMatthew G. Knepley         }
6688a5e93ea8SMatthew G. Knepley       }
6689a5e93ea8SMatthew G. Knepley     }
6690a5e93ea8SMatthew G. Knepley   }
66913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6692a5e93ea8SMatthew G. Knepley }
6693a5e93ea8SMatthew G. Knepley 
6694d71ae5a4SJacob 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[])
6695d71ae5a4SJacob Faibussowitsch {
6696552f7358SJed Brown   PetscScalar    *a;
66971a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
66981a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
669997e99dd9SToby Isaac   PetscInt        cind = 0, b;
6700552f7358SJed Brown 
6701552f7358SJed Brown   PetscFunctionBegin;
67029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
67039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
67049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
67051a271a75SMatthew G. Knepley   a = &array[foff];
6706552f7358SJed Brown   if (!fcdof || setBC) {
670797e99dd9SToby Isaac     if (clperm) {
67089371c9d4SSatish Balay       if (perm) {
6709ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6710552f7358SJed Brown       } else {
6711ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
67129371c9d4SSatish Balay       }
67139371c9d4SSatish Balay     } else {
67149371c9d4SSatish Balay       if (perm) {
6715ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
67169371c9d4SSatish Balay       } else {
6717ad540459SPierre Jolivet         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
67189371c9d4SSatish Balay       }
6719552f7358SJed Brown     }
6720552f7358SJed Brown   } else {
67219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
672297e99dd9SToby Isaac     if (clperm) {
672397e99dd9SToby Isaac       if (perm) {
672497e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
67259371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
67269371c9d4SSatish Balay             ++cind;
67279371c9d4SSatish Balay             continue;
67289371c9d4SSatish Balay           }
672997e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6730552f7358SJed Brown         }
6731552f7358SJed Brown       } else {
673297e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
67339371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
67349371c9d4SSatish Balay             ++cind;
67359371c9d4SSatish Balay             continue;
67369371c9d4SSatish Balay           }
673797e99dd9SToby Isaac           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
673897e99dd9SToby Isaac         }
673997e99dd9SToby Isaac       }
674097e99dd9SToby Isaac     } else {
674197e99dd9SToby Isaac       if (perm) {
674297e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
67439371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
67449371c9d4SSatish Balay             ++cind;
67459371c9d4SSatish Balay             continue;
67469371c9d4SSatish Balay           }
674797e99dd9SToby Isaac           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
674897e99dd9SToby Isaac         }
674997e99dd9SToby Isaac       } else {
675097e99dd9SToby Isaac         for (b = 0; b < fdof; b++) {
67519371c9d4SSatish Balay           if ((cind < fcdof) && (b == fcdofs[cind])) {
67529371c9d4SSatish Balay             ++cind;
67539371c9d4SSatish Balay             continue;
67549371c9d4SSatish Balay           }
675597e99dd9SToby Isaac           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6756552f7358SJed Brown         }
6757552f7358SJed Brown       }
6758552f7358SJed Brown     }
6759552f7358SJed Brown   }
67601a271a75SMatthew G. Knepley   *offset += fdof;
67613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6762552f7358SJed Brown }
6763552f7358SJed Brown 
6764d71ae5a4SJacob 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[])
6765d71ae5a4SJacob Faibussowitsch {
6766a5e93ea8SMatthew G. Knepley   PetscScalar    *a;
67671a271a75SMatthew G. Knepley   PetscInt        fdof, foff, fcdof, foffset = *offset;
67681a271a75SMatthew G. Knepley   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
67695da9d227SMatthew G. Knepley   PetscInt        Nc, cind = 0, ncind = 0, b;
6770ba322698SMatthew G. Knepley   PetscBool       ncSet, fcSet;
6771a5e93ea8SMatthew G. Knepley 
6772a5e93ea8SMatthew G. Knepley   PetscFunctionBegin;
67739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
67749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
67759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
67769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
67771a271a75SMatthew G. Knepley   a = &array[foff];
6778a5e93ea8SMatthew G. Knepley   if (fcdof) {
6779ba322698SMatthew G. Knepley     /* We just override fcdof and fcdofs with Ncc and comps */
67809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
678197e99dd9SToby Isaac     if (clperm) {
678297e99dd9SToby Isaac       if (perm) {
6783ba322698SMatthew G. Knepley         if (comps) {
6784ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6785ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
67869371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
67879371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
67889371c9d4SSatish Balay               ncSet = PETSC_TRUE;
67899371c9d4SSatish Balay             }
67909371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
67919371c9d4SSatish Balay               ++cind;
67929371c9d4SSatish Balay               fcSet = PETSC_TRUE;
67939371c9d4SSatish Balay             }
6794ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6795ba322698SMatthew G. Knepley           }
6796ba322698SMatthew G. Knepley         } else {
679797e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
679897e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
679997e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6800a5e93ea8SMatthew G. Knepley               ++cind;
6801a5e93ea8SMatthew G. Knepley             }
6802a5e93ea8SMatthew G. Knepley           }
6803ba322698SMatthew G. Knepley         }
6804ba322698SMatthew G. Knepley       } else {
6805ba322698SMatthew G. Knepley         if (comps) {
6806ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6807ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
68089371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
68099371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
68109371c9d4SSatish Balay               ncSet = PETSC_TRUE;
68119371c9d4SSatish Balay             }
68129371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
68139371c9d4SSatish Balay               ++cind;
68149371c9d4SSatish Balay               fcSet = PETSC_TRUE;
68159371c9d4SSatish Balay             }
6816ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6817ba322698SMatthew G. Knepley           }
6818a5e93ea8SMatthew G. Knepley         } else {
681997e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
682097e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
682197e99dd9SToby Isaac               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
682297e99dd9SToby Isaac               ++cind;
682397e99dd9SToby Isaac             }
682497e99dd9SToby Isaac           }
682597e99dd9SToby Isaac         }
6826ba322698SMatthew G. Knepley       }
682797e99dd9SToby Isaac     } else {
682897e99dd9SToby Isaac       if (perm) {
6829ba322698SMatthew G. Knepley         if (comps) {
6830ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6831ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
68329371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
68339371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
68349371c9d4SSatish Balay               ncSet = PETSC_TRUE;
68359371c9d4SSatish Balay             }
68369371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
68379371c9d4SSatish Balay               ++cind;
68389371c9d4SSatish Balay               fcSet = PETSC_TRUE;
68399371c9d4SSatish Balay             }
6840ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6841ba322698SMatthew G. Knepley           }
6842ba322698SMatthew G. Knepley         } else {
684397e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
684497e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
684597e99dd9SToby Isaac               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
684697e99dd9SToby Isaac               ++cind;
684797e99dd9SToby Isaac             }
684897e99dd9SToby Isaac           }
6849ba322698SMatthew G. Knepley         }
6850ba322698SMatthew G. Knepley       } else {
6851ba322698SMatthew G. Knepley         if (comps) {
6852ba322698SMatthew G. Knepley           for (b = 0; b < fdof; b++) {
6853ba322698SMatthew G. Knepley             ncSet = fcSet = PETSC_FALSE;
68549371c9d4SSatish Balay             if (b % Nc == comps[ncind]) {
68559371c9d4SSatish Balay               ncind = (ncind + 1) % Ncc;
68569371c9d4SSatish Balay               ncSet = PETSC_TRUE;
68579371c9d4SSatish Balay             }
68589371c9d4SSatish Balay             if ((cind < fcdof) && (b == fcdofs[cind])) {
68599371c9d4SSatish Balay               ++cind;
68609371c9d4SSatish Balay               fcSet = PETSC_TRUE;
68619371c9d4SSatish Balay             }
6862ad540459SPierre Jolivet             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6863ba322698SMatthew G. Knepley           }
686497e99dd9SToby Isaac         } else {
686597e99dd9SToby Isaac           for (b = 0; b < fdof; b++) {
686697e99dd9SToby Isaac             if ((cind < fcdof) && (b == fcdofs[cind])) {
686797e99dd9SToby Isaac               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6868a5e93ea8SMatthew G. Knepley               ++cind;
6869a5e93ea8SMatthew G. Knepley             }
6870a5e93ea8SMatthew G. Knepley           }
6871a5e93ea8SMatthew G. Knepley         }
6872a5e93ea8SMatthew G. Knepley       }
6873a5e93ea8SMatthew G. Knepley     }
6874ba322698SMatthew G. Knepley   }
68751a271a75SMatthew G. Knepley   *offset += fdof;
68763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6877a5e93ea8SMatthew G. Knepley }
6878a5e93ea8SMatthew G. Knepley 
6879d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6880d71ae5a4SJacob Faibussowitsch {
6881552f7358SJed Brown   PetscScalar    *array;
68821b406b76SMatthew G. Knepley   const PetscInt *cone, *coneO;
68831b406b76SMatthew G. Knepley   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6884552f7358SJed Brown 
68851b406b76SMatthew G. Knepley   PetscFunctionBeginHot;
68869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
68879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
68889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
68899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
68909566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
6891b6ebb6e6SMatthew G. Knepley   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6892b6ebb6e6SMatthew G. Knepley     const PetscInt cp = !p ? point : cone[p - 1];
6893b6ebb6e6SMatthew G. Knepley     const PetscInt o  = !p ? 0 : coneO[p - 1];
6894b6ebb6e6SMatthew G. Knepley 
68959371c9d4SSatish Balay     if ((cp < pStart) || (cp >= pEnd)) {
68969371c9d4SSatish Balay       dof = 0;
68979371c9d4SSatish Balay       continue;
68989371c9d4SSatish Balay     }
68999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, cp, &dof));
6900b6ebb6e6SMatthew G. Knepley     /* ADD_VALUES */
6901b6ebb6e6SMatthew G. Knepley     {
6902b6ebb6e6SMatthew G. Knepley       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6903b6ebb6e6SMatthew G. Knepley       PetscScalar    *a;
6904b6ebb6e6SMatthew G. Knepley       PetscInt        cdof, coff, cind = 0, k;
6905b6ebb6e6SMatthew G. Knepley 
69069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
69079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6908b6ebb6e6SMatthew G. Knepley       a = &array[coff];
6909b6ebb6e6SMatthew G. Knepley       if (!cdof) {
6910b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6911ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6912b6ebb6e6SMatthew G. Knepley         } else {
6913ad540459SPierre Jolivet           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6914b6ebb6e6SMatthew G. Knepley         }
6915b6ebb6e6SMatthew G. Knepley       } else {
69169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6917b6ebb6e6SMatthew G. Knepley         if (o >= 0) {
6918b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
69199371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
69209371c9d4SSatish Balay               ++cind;
69219371c9d4SSatish Balay               continue;
69229371c9d4SSatish Balay             }
6923b6ebb6e6SMatthew G. Knepley             a[k] += values[off + k];
6924b6ebb6e6SMatthew G. Knepley           }
6925b6ebb6e6SMatthew G. Knepley         } else {
6926b6ebb6e6SMatthew G. Knepley           for (k = 0; k < dof; ++k) {
69279371c9d4SSatish Balay             if ((cind < cdof) && (k == cdofs[cind])) {
69289371c9d4SSatish Balay               ++cind;
69299371c9d4SSatish Balay               continue;
69309371c9d4SSatish Balay             }
6931b6ebb6e6SMatthew G. Knepley             a[k] += values[off + dof - k - 1];
6932b6ebb6e6SMatthew G. Knepley           }
6933b6ebb6e6SMatthew G. Knepley         }
6934b6ebb6e6SMatthew G. Knepley       }
6935b6ebb6e6SMatthew G. Knepley     }
6936b6ebb6e6SMatthew G. Knepley   }
69379566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
69383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6939b6ebb6e6SMatthew G. Knepley }
69401b406b76SMatthew G. Knepley 
69411b406b76SMatthew G. Knepley /*@C
694220f4b53cSBarry Smith   DMPlexVecSetClosure - Set an array of the values on the closure of `point`
69431b406b76SMatthew G. Knepley 
69441b406b76SMatthew G. Knepley   Not collective
69451b406b76SMatthew G. Knepley 
69461b406b76SMatthew G. Knepley   Input Parameters:
6947a1cb98faSBarry Smith + dm      - The `DM`
694820f4b53cSBarry Smith . section - The section describing the layout in `v`, or `NULL` to use the default section
69491b406b76SMatthew G. Knepley . v       - The local vector
695020f4b53cSBarry Smith . point   - The point in the `DM`
69511b406b76SMatthew G. Knepley . values  - The array of values
6952a1cb98faSBarry Smith - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6953a1cb98faSBarry Smith          where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
69541b406b76SMatthew G. Knepley 
69551b406b76SMatthew G. Knepley   Level: intermediate
69561b406b76SMatthew G. Knepley 
69571cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
69581b406b76SMatthew G. Knepley @*/
6959d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6960d71ae5a4SJacob Faibussowitsch {
69611b406b76SMatthew G. Knepley   PetscSection    clSection;
69621b406b76SMatthew G. Knepley   IS              clPoints;
69631b406b76SMatthew G. Knepley   PetscScalar    *array;
69641b406b76SMatthew G. Knepley   PetscInt       *points = NULL;
696527f02ce8SMatthew G. Knepley   const PetscInt *clp, *clperm = NULL;
6966c459fbc1SJed Brown   PetscInt        depth, numFields, numPoints, p, clsize;
69671b406b76SMatthew G. Knepley 
69681a271a75SMatthew G. Knepley   PetscFunctionBeginHot;
69691b406b76SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
69709566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
69711a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
69721a271a75SMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
69739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
69749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
69751b406b76SMatthew G. Knepley   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
69769566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
69773ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
69781b406b76SMatthew G. Knepley   }
69791a271a75SMatthew G. Knepley   /* Get points */
698007218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6981c459fbc1SJed Brown   for (clsize = 0, p = 0; p < numPoints; p++) {
6982c459fbc1SJed Brown     PetscInt dof;
69839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6984c459fbc1SJed Brown     clsize += dof;
6985c459fbc1SJed Brown   }
69869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
69871a271a75SMatthew G. Knepley   /* Get array */
69889566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
69891a271a75SMatthew G. Knepley   /* Get values */
6990ef90cfe2SMatthew G. Knepley   if (numFields > 0) {
699197e99dd9SToby Isaac     PetscInt offset = 0, f;
6992552f7358SJed Brown     for (f = 0; f < numFields; ++f) {
699397e99dd9SToby Isaac       const PetscInt    **perms = NULL;
699497e99dd9SToby Isaac       const PetscScalar **flips = NULL;
699597e99dd9SToby Isaac 
69969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6997552f7358SJed Brown       switch (mode) {
6998552f7358SJed Brown       case INSERT_VALUES:
699997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
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;
70033ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
70049371c9d4SSatish Balay         }
70059371c9d4SSatish Balay         break;
7006552f7358SJed Brown       case INSERT_ALL_VALUES:
700797e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
700897e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
700997e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
701097e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
70113ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
70129371c9d4SSatish Balay         }
70139371c9d4SSatish Balay         break;
7014a5e93ea8SMatthew G. Knepley       case INSERT_BC_VALUES:
701597e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
701697e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
701797e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
701897e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
70193ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
70209371c9d4SSatish Balay         }
70219371c9d4SSatish Balay         break;
7022552f7358SJed Brown       case ADD_VALUES:
702397e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
702497e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
702597e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
702697e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
70273ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
70289371c9d4SSatish Balay         }
70299371c9d4SSatish Balay         break;
7030552f7358SJed Brown       case ADD_ALL_VALUES:
703197e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
703297e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
703397e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
703497e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
70353ba16761SJacob Faibussowitsch           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
70369371c9d4SSatish Balay         }
70379371c9d4SSatish Balay         break;
7038304ab55fSMatthew G. Knepley       case ADD_BC_VALUES:
703997e99dd9SToby Isaac         for (p = 0; p < numPoints; p++) {
704097e99dd9SToby Isaac           const PetscInt     point = points[2 * p];
704197e99dd9SToby Isaac           const PetscInt    *perm  = perms ? perms[p] : NULL;
704297e99dd9SToby Isaac           const PetscScalar *flip  = flips ? flips[p] : NULL;
70433ba16761SJacob Faibussowitsch           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
70449371c9d4SSatish Balay         }
70459371c9d4SSatish Balay         break;
7046d71ae5a4SJacob Faibussowitsch       default:
7047d71ae5a4SJacob Faibussowitsch         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7048552f7358SJed Brown       }
70499566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
70501a271a75SMatthew G. Knepley     }
7051552f7358SJed Brown   } else {
70521a271a75SMatthew G. Knepley     PetscInt            dof, off;
705397e99dd9SToby Isaac     const PetscInt    **perms = NULL;
705497e99dd9SToby Isaac     const PetscScalar **flips = NULL;
70551a271a75SMatthew G. Knepley 
70569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
7057552f7358SJed Brown     switch (mode) {
7058552f7358SJed Brown     case INSERT_VALUES:
705997e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
706097e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
706197e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
706297e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70643ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
70659371c9d4SSatish Balay       }
70669371c9d4SSatish Balay       break;
7067552f7358SJed Brown     case INSERT_ALL_VALUES:
706897e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
706997e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
707097e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
707197e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70733ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
70749371c9d4SSatish Balay       }
70759371c9d4SSatish Balay       break;
7076a5e93ea8SMatthew G. Knepley     case INSERT_BC_VALUES:
707797e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
707897e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
707997e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
708097e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70823ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
70839371c9d4SSatish Balay       }
70849371c9d4SSatish Balay       break;
7085552f7358SJed Brown     case ADD_VALUES:
708697e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
708797e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
708897e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
708997e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
70913ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
70929371c9d4SSatish Balay       }
70939371c9d4SSatish Balay       break;
7094552f7358SJed Brown     case ADD_ALL_VALUES:
709597e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
709697e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
709797e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
709897e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
70999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
71003ba16761SJacob Faibussowitsch         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
71019371c9d4SSatish Balay       }
71029371c9d4SSatish Balay       break;
7103304ab55fSMatthew G. Knepley     case ADD_BC_VALUES:
710497e99dd9SToby Isaac       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
710597e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
710697e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
710797e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
71089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, point, &dof));
71093ba16761SJacob Faibussowitsch         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
71109371c9d4SSatish Balay       }
71119371c9d4SSatish Balay       break;
7112d71ae5a4SJacob Faibussowitsch     default:
7113d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7114552f7358SJed Brown     }
71159566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
7116552f7358SJed Brown   }
71171a271a75SMatthew G. Knepley   /* Cleanup points */
71189566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
71191a271a75SMatthew G. Knepley   /* Cleanup array */
71209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
71213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7122552f7358SJed Brown }
7123552f7358SJed Brown 
71245f790a90SMatthew G. Knepley /* Check whether the given point is in the label. If not, update the offset to skip this point */
7125d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
7126d71ae5a4SJacob Faibussowitsch {
71275f790a90SMatthew G. Knepley   PetscFunctionBegin;
712811cc89d2SBarry Smith   *contains = PETSC_TRUE;
71295f790a90SMatthew G. Knepley   if (label) {
7130d6177c40SToby Isaac     PetscInt fdof;
71315f790a90SMatthew G. Knepley 
713211cc89d2SBarry Smith     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
713311cc89d2SBarry Smith     if (!*contains) {
71349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
71355f790a90SMatthew G. Knepley       *offset += fdof;
71363ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
71375f790a90SMatthew G. Knepley     }
71385f790a90SMatthew G. Knepley   }
71393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
71405f790a90SMatthew G. Knepley }
71415f790a90SMatthew G. Knepley 
714297529cf3SJed Brown /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
7143d71ae5a4SJacob 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)
7144d71ae5a4SJacob Faibussowitsch {
7145e07394fbSMatthew G. Knepley   PetscSection    clSection;
7146e07394fbSMatthew G. Knepley   IS              clPoints;
7147e07394fbSMatthew G. Knepley   PetscScalar    *array;
7148e07394fbSMatthew G. Knepley   PetscInt       *points = NULL;
714997529cf3SJed Brown   const PetscInt *clp;
7150e07394fbSMatthew G. Knepley   PetscInt        numFields, numPoints, p;
715197e99dd9SToby Isaac   PetscInt        offset = 0, f;
7152e07394fbSMatthew G. Knepley 
7153e07394fbSMatthew G. Knepley   PetscFunctionBeginHot;
7154e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
71559566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7156e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7157e07394fbSMatthew G. Knepley   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
71589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7159e07394fbSMatthew G. Knepley   /* Get points */
716007218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
7161e07394fbSMatthew G. Knepley   /* Get array */
71629566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &array));
7163e07394fbSMatthew G. Knepley   /* Get values */
7164e07394fbSMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
716597e99dd9SToby Isaac     const PetscInt    **perms = NULL;
716697e99dd9SToby Isaac     const PetscScalar **flips = NULL;
716711cc89d2SBarry Smith     PetscBool           contains;
716897e99dd9SToby Isaac 
7169e07394fbSMatthew G. Knepley     if (!fieldActive[f]) {
7170e07394fbSMatthew G. Knepley       for (p = 0; p < numPoints * 2; p += 2) {
7171e07394fbSMatthew G. Knepley         PetscInt fdof;
71729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7173e07394fbSMatthew G. Knepley         offset += fdof;
7174e07394fbSMatthew G. Knepley       }
7175e07394fbSMatthew G. Knepley       continue;
7176e07394fbSMatthew G. Knepley     }
71779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7178e07394fbSMatthew G. Knepley     switch (mode) {
7179e07394fbSMatthew G. Knepley     case INSERT_VALUES:
718097e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
718197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
718297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
718397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
718411cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
718511cc89d2SBarry Smith         if (!contains) continue;
71869566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
71879371c9d4SSatish Balay       }
71889371c9d4SSatish Balay       break;
7189e07394fbSMatthew G. Knepley     case INSERT_ALL_VALUES:
719097e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
719197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
719297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
719397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
719411cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
719511cc89d2SBarry Smith         if (!contains) continue;
71969566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
71979371c9d4SSatish Balay       }
71989371c9d4SSatish Balay       break;
7199e07394fbSMatthew G. Knepley     case INSERT_BC_VALUES:
720097e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
720197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
720297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
720397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
720411cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
720511cc89d2SBarry Smith         if (!contains) continue;
72069566063dSJacob Faibussowitsch         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
72079371c9d4SSatish Balay       }
72089371c9d4SSatish Balay       break;
7209e07394fbSMatthew G. Knepley     case ADD_VALUES:
721097e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
721197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
721297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
721397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
721411cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
721511cc89d2SBarry Smith         if (!contains) continue;
72169566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
72179371c9d4SSatish Balay       }
72189371c9d4SSatish Balay       break;
7219e07394fbSMatthew G. Knepley     case ADD_ALL_VALUES:
722097e99dd9SToby Isaac       for (p = 0; p < numPoints; p++) {
722197e99dd9SToby Isaac         const PetscInt     point = points[2 * p];
722297e99dd9SToby Isaac         const PetscInt    *perm  = perms ? perms[p] : NULL;
722397e99dd9SToby Isaac         const PetscScalar *flip  = flips ? flips[p] : NULL;
722411cc89d2SBarry Smith         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
722511cc89d2SBarry Smith         if (!contains) continue;
72269566063dSJacob Faibussowitsch         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
72279371c9d4SSatish Balay       }
72289371c9d4SSatish Balay       break;
7229d71ae5a4SJacob Faibussowitsch     default:
7230d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
7231e07394fbSMatthew G. Knepley     }
72329566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
7233e07394fbSMatthew G. Knepley   }
7234e07394fbSMatthew G. Knepley   /* Cleanup points */
72359566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
7236e07394fbSMatthew G. Knepley   /* Cleanup array */
72379566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &array));
72383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7239e07394fbSMatthew G. Knepley }
7240e07394fbSMatthew G. Knepley 
7241d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
7242d71ae5a4SJacob Faibussowitsch {
7243552f7358SJed Brown   PetscMPIInt rank;
7244552f7358SJed Brown   PetscInt    i, j;
7245552f7358SJed Brown 
7246552f7358SJed Brown   PetscFunctionBegin;
72479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
724863a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
724963a3b9bcSJacob Faibussowitsch   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
725063a3b9bcSJacob Faibussowitsch   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
7251b0ecff45SMatthew G. Knepley   numCIndices = numCIndices ? numCIndices : numRIndices;
72523ba16761SJacob Faibussowitsch   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
7253b0ecff45SMatthew G. Knepley   for (i = 0; i < numRIndices; i++) {
72549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
7255b0ecff45SMatthew G. Knepley     for (j = 0; j < numCIndices; j++) {
7256519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
72579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
7258552f7358SJed Brown #else
72599566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
7260552f7358SJed Brown #endif
7261552f7358SJed Brown     }
72629566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
7263552f7358SJed Brown   }
72643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7265552f7358SJed Brown }
7266552f7358SJed Brown 
726705586334SMatthew G. Knepley /*
726805586334SMatthew G. Knepley   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
726905586334SMatthew G. Knepley 
727005586334SMatthew G. Knepley   Input Parameters:
727105586334SMatthew G. Knepley + section - The section for this data layout
727236fa2b79SJed Brown . islocal - Is the section (and thus indices being requested) local or global?
727305586334SMatthew G. Knepley . point   - The point contributing dofs with these indices
727405586334SMatthew G. Knepley . off     - The global offset of this point
727505586334SMatthew G. Knepley . loff    - The local offset of each field
7276a5b23f4aSJose E. Roman . setBC   - The flag determining whether to include indices of boundary values
727705586334SMatthew G. Knepley . perm    - A permutation of the dofs on this point, or NULL
727805586334SMatthew G. Knepley - indperm - A permutation of the entire indices array, or NULL
727905586334SMatthew G. Knepley 
728005586334SMatthew G. Knepley   Output Parameter:
728105586334SMatthew G. Knepley . indices - Indices for dofs on this point
728205586334SMatthew G. Knepley 
728305586334SMatthew G. Knepley   Level: developer
728405586334SMatthew G. Knepley 
728505586334SMatthew G. Knepley   Note: The indices could be local or global, depending on the value of 'off'.
728605586334SMatthew G. Knepley */
7287d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
7288d71ae5a4SJacob Faibussowitsch {
7289e6ccafaeSMatthew G Knepley   PetscInt        dof;   /* The number of unknowns on this point */
7290552f7358SJed Brown   PetscInt        cdof;  /* The number of constraints on this point */
7291552f7358SJed Brown   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7292552f7358SJed Brown   PetscInt        cind = 0, k;
7293552f7358SJed Brown 
7294552f7358SJed Brown   PetscFunctionBegin;
729508401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
72969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(section, point, &dof));
72979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7298552f7358SJed Brown   if (!cdof || setBC) {
729905586334SMatthew G. Knepley     for (k = 0; k < dof; ++k) {
730005586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
730105586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
730205586334SMatthew G. Knepley 
730305586334SMatthew G. Knepley       indices[ind] = off + k;
7304552f7358SJed Brown     }
7305552f7358SJed Brown   } else {
73069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
73074acb8e1eSToby Isaac     for (k = 0; k < dof; ++k) {
730805586334SMatthew G. Knepley       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
730905586334SMatthew G. Knepley       const PetscInt ind    = indperm ? indperm[preind] : preind;
731005586334SMatthew G. Knepley 
73114acb8e1eSToby Isaac       if ((cind < cdof) && (k == cdofs[cind])) {
73124acb8e1eSToby Isaac         /* Insert check for returning constrained indices */
731305586334SMatthew G. Knepley         indices[ind] = -(off + k + 1);
73144acb8e1eSToby Isaac         ++cind;
73154acb8e1eSToby Isaac       } else {
731636fa2b79SJed Brown         indices[ind] = off + k - (islocal ? 0 : cind);
7317552f7358SJed Brown       }
7318552f7358SJed Brown     }
7319552f7358SJed Brown   }
7320e6ccafaeSMatthew G Knepley   *loff += dof;
73213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7322552f7358SJed Brown }
7323552f7358SJed Brown 
73247e29afd2SMatthew G. Knepley /*
732536fa2b79SJed Brown  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
73267e29afd2SMatthew G. Knepley 
732736fa2b79SJed Brown  Input Parameters:
732836fa2b79SJed Brown + section - a section (global or local)
732920f4b53cSBarry Smith - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
733036fa2b79SJed Brown . point - point within section
733136fa2b79SJed Brown . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
733236fa2b79SJed Brown . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
733336fa2b79SJed Brown . setBC - identify constrained (boundary condition) points via involution.
733436fa2b79SJed Brown . perms - perms[f][permsoff][:] is a permutation of dofs within each field
733536fa2b79SJed Brown . permsoff - offset
733636fa2b79SJed Brown - indperm - index permutation
733736fa2b79SJed Brown 
733836fa2b79SJed Brown  Output Parameter:
733936fa2b79SJed Brown . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
734036fa2b79SJed Brown . indices - array to hold indices (as defined by section) of each dof associated with point
734136fa2b79SJed Brown 
734236fa2b79SJed Brown  Notes:
734336fa2b79SJed Brown  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
734436fa2b79SJed Brown  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
734536fa2b79SJed Brown  in the local vector.
734636fa2b79SJed Brown 
734736fa2b79SJed Brown  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
734836fa2b79SJed Brown  significant).  It is invalid to call with a global section and setBC=true.
734936fa2b79SJed Brown 
735036fa2b79SJed Brown  Developer Note:
735136fa2b79SJed Brown  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
735236fa2b79SJed Brown  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
735336fa2b79SJed Brown  offset could be obtained from the section instead of passing it explicitly as we do now.
735436fa2b79SJed Brown 
735536fa2b79SJed Brown  Example:
735636fa2b79SJed Brown  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
735736fa2b79SJed Brown  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
735836fa2b79SJed Brown  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
735936fa2b79SJed 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.
736036fa2b79SJed Brown 
736136fa2b79SJed Brown  Level: developer
73627e29afd2SMatthew G. Knepley */
7363d71ae5a4SJacob 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[])
7364d71ae5a4SJacob Faibussowitsch {
7365552f7358SJed Brown   PetscInt numFields, foff, f;
7366552f7358SJed Brown 
7367552f7358SJed Brown   PetscFunctionBegin;
736808401ef6SPierre Jolivet   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
73699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7370552f7358SJed Brown   for (f = 0, foff = 0; f < numFields; ++f) {
73714acb8e1eSToby Isaac     PetscInt        fdof, cfdof;
7372552f7358SJed Brown     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
73734acb8e1eSToby Isaac     PetscInt        cind = 0, b;
73744acb8e1eSToby Isaac     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7375552f7358SJed Brown 
73769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
73779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7378552f7358SJed Brown     if (!cfdof || setBC) {
737905586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
738005586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
738105586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
738205586334SMatthew G. Knepley 
738305586334SMatthew G. Knepley         indices[ind] = off + foff + b;
738405586334SMatthew G. Knepley       }
7385552f7358SJed Brown     } else {
73869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
738705586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
738805586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
738905586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
739005586334SMatthew G. Knepley 
73914acb8e1eSToby Isaac         if ((cind < cfdof) && (b == fcdofs[cind])) {
739205586334SMatthew G. Knepley           indices[ind] = -(off + foff + b + 1);
7393552f7358SJed Brown           ++cind;
7394552f7358SJed Brown         } else {
739536fa2b79SJed Brown           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7396552f7358SJed Brown         }
7397552f7358SJed Brown       }
7398552f7358SJed Brown     }
739936fa2b79SJed Brown     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7400552f7358SJed Brown     foffs[f] += fdof;
7401552f7358SJed Brown   }
74023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7403552f7358SJed Brown }
7404552f7358SJed Brown 
74057e29afd2SMatthew G. Knepley /*
74067e29afd2SMatthew G. Knepley   This version believes the globalSection offsets for each field, rather than just the point offset
74077e29afd2SMatthew G. Knepley 
74087e29afd2SMatthew G. Knepley  . foffs - The offset into 'indices' for each field, since it is segregated by field
7409645102dcSJed Brown 
7410645102dcSJed Brown  Notes:
7411645102dcSJed Brown  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7412645102dcSJed Brown  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
74137e29afd2SMatthew G. Knepley */
7414d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7415d71ae5a4SJacob Faibussowitsch {
74167e29afd2SMatthew G. Knepley   PetscInt numFields, foff, f;
74177e29afd2SMatthew G. Knepley 
74187e29afd2SMatthew G. Knepley   PetscFunctionBegin;
74199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
74207e29afd2SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
74217e29afd2SMatthew G. Knepley     PetscInt        fdof, cfdof;
74227e29afd2SMatthew G. Knepley     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
74237e29afd2SMatthew G. Knepley     PetscInt        cind = 0, b;
74247e29afd2SMatthew G. Knepley     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
74257e29afd2SMatthew G. Knepley 
74269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
74279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
74289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7429645102dcSJed Brown     if (!cfdof) {
743005586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
743105586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
743205586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
743305586334SMatthew G. Knepley 
743405586334SMatthew G. Knepley         indices[ind] = foff + b;
743505586334SMatthew G. Knepley       }
74367e29afd2SMatthew G. Knepley     } else {
74379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
743805586334SMatthew G. Knepley       for (b = 0; b < fdof; ++b) {
743905586334SMatthew G. Knepley         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
744005586334SMatthew G. Knepley         const PetscInt ind    = indperm ? indperm[preind] : preind;
744105586334SMatthew G. Knepley 
74427e29afd2SMatthew G. Knepley         if ((cind < cfdof) && (b == fcdofs[cind])) {
744305586334SMatthew G. Knepley           indices[ind] = -(foff + b + 1);
74447e29afd2SMatthew G. Knepley           ++cind;
74457e29afd2SMatthew G. Knepley         } else {
744605586334SMatthew G. Knepley           indices[ind] = foff + b - cind;
74477e29afd2SMatthew G. Knepley         }
74487e29afd2SMatthew G. Knepley       }
74497e29afd2SMatthew G. Knepley     }
74507e29afd2SMatthew G. Knepley     foffs[f] += fdof;
74517e29afd2SMatthew G. Knepley   }
74523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
74537e29afd2SMatthew G. Knepley }
74547e29afd2SMatthew G. Knepley 
7455d71ae5a4SJacob 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)
7456d71ae5a4SJacob Faibussowitsch {
7457d3d1a6afSToby Isaac   Mat             cMat;
7458d3d1a6afSToby Isaac   PetscSection    aSec, cSec;
7459d3d1a6afSToby Isaac   IS              aIS;
7460d3d1a6afSToby Isaac   PetscInt        aStart = -1, aEnd = -1;
7461d3d1a6afSToby Isaac   const PetscInt *anchors;
7462e17c06e0SMatthew G. Knepley   PetscInt        numFields, f, p, q, newP = 0;
7463d3d1a6afSToby Isaac   PetscInt        newNumPoints = 0, newNumIndices = 0;
7464d3d1a6afSToby Isaac   PetscInt       *newPoints, *indices, *newIndices;
7465d3d1a6afSToby Isaac   PetscInt        maxAnchor, maxDof;
7466d3d1a6afSToby Isaac   PetscInt        newOffsets[32];
7467d3d1a6afSToby Isaac   PetscInt       *pointMatOffsets[32];
7468d3d1a6afSToby Isaac   PetscInt       *newPointOffsets[32];
7469d3d1a6afSToby Isaac   PetscScalar    *pointMat[32];
74706ecaa68aSToby Isaac   PetscScalar    *newValues      = NULL, *tmpValues;
7471d3d1a6afSToby Isaac   PetscBool       anyConstrained = PETSC_FALSE;
7472d3d1a6afSToby Isaac 
7473d3d1a6afSToby Isaac   PetscFunctionBegin;
7474d3d1a6afSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7475d3d1a6afSToby Isaac   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
74769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
7477d3d1a6afSToby Isaac 
74789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7479d3d1a6afSToby Isaac   /* if there are point-to-point constraints */
7480d3d1a6afSToby Isaac   if (aSec) {
74819566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(newOffsets, 32));
74829566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(aIS, &anchors));
74839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7484d3d1a6afSToby Isaac     /* figure out how many points are going to be in the new element matrix
7485d3d1a6afSToby Isaac      * (we allow double counting, because it's all just going to be summed
7486d3d1a6afSToby Isaac      * into the global matrix anyway) */
7487d3d1a6afSToby Isaac     for (p = 0; p < 2 * numPoints; p += 2) {
7488d3d1a6afSToby Isaac       PetscInt b    = points[p];
74894b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7490d3d1a6afSToby Isaac 
74919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7492ad540459SPierre Jolivet       if (!bSecDof) continue;
749348a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7494d3d1a6afSToby Isaac       if (bDof) {
7495d3d1a6afSToby Isaac         /* this point is constrained */
7496d3d1a6afSToby Isaac         /* it is going to be replaced by its anchors */
7497d3d1a6afSToby Isaac         PetscInt bOff, q;
7498d3d1a6afSToby Isaac 
7499d3d1a6afSToby Isaac         anyConstrained = PETSC_TRUE;
7500d3d1a6afSToby Isaac         newNumPoints += bDof;
75019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7502d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7503d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q];
7504d3d1a6afSToby Isaac           PetscInt aDof;
7505d3d1a6afSToby Isaac 
75069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7507d3d1a6afSToby Isaac           newNumIndices += aDof;
7508d3d1a6afSToby Isaac           for (f = 0; f < numFields; ++f) {
7509d3d1a6afSToby Isaac             PetscInt fDof;
7510d3d1a6afSToby Isaac 
75119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7512d3d1a6afSToby Isaac             newOffsets[f + 1] += fDof;
7513d3d1a6afSToby Isaac           }
7514d3d1a6afSToby Isaac         }
75159371c9d4SSatish Balay       } else {
7516d3d1a6afSToby Isaac         /* this point is not constrained */
7517d3d1a6afSToby Isaac         newNumPoints++;
75184b2f2278SToby Isaac         newNumIndices += bSecDof;
7519d3d1a6afSToby Isaac         for (f = 0; f < numFields; ++f) {
7520d3d1a6afSToby Isaac           PetscInt fDof;
7521d3d1a6afSToby Isaac 
75229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7523d3d1a6afSToby Isaac           newOffsets[f + 1] += fDof;
7524d3d1a6afSToby Isaac         }
7525d3d1a6afSToby Isaac       }
7526d3d1a6afSToby Isaac     }
7527d3d1a6afSToby Isaac   }
7528d3d1a6afSToby Isaac   if (!anyConstrained) {
752972b80496SMatthew G. Knepley     if (outNumPoints) *outNumPoints = 0;
753072b80496SMatthew G. Knepley     if (outNumIndices) *outNumIndices = 0;
753172b80496SMatthew G. Knepley     if (outPoints) *outPoints = NULL;
753272b80496SMatthew G. Knepley     if (outValues) *outValues = NULL;
75339566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
75343ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7535d3d1a6afSToby Isaac   }
7536d3d1a6afSToby Isaac 
75376ecaa68aSToby Isaac   if (outNumPoints) *outNumPoints = newNumPoints;
75386ecaa68aSToby Isaac   if (outNumIndices) *outNumIndices = newNumIndices;
75396ecaa68aSToby Isaac 
7540f13f9184SToby Isaac   for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7541d3d1a6afSToby Isaac 
75426ecaa68aSToby Isaac   if (!outPoints && !outValues) {
75436ecaa68aSToby Isaac     if (offsets) {
7544ad540459SPierre Jolivet       for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
75456ecaa68aSToby Isaac     }
75469566063dSJacob Faibussowitsch     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
75473ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
75486ecaa68aSToby Isaac   }
75496ecaa68aSToby Isaac 
75501dca8a05SBarry 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);
7551d3d1a6afSToby Isaac 
75529566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7553d3d1a6afSToby Isaac 
7554d3d1a6afSToby Isaac   /* workspaces */
7555d3d1a6afSToby Isaac   if (numFields) {
7556d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
75579566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
75589566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7559d3d1a6afSToby Isaac     }
75609371c9d4SSatish Balay   } else {
75619566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
75629566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0]));
7563d3d1a6afSToby Isaac   }
7564d3d1a6afSToby Isaac 
7565d3d1a6afSToby Isaac   /* get workspaces for the point-to-point matrices */
7566d3d1a6afSToby Isaac   if (numFields) {
75674b2f2278SToby Isaac     PetscInt totalOffset, totalMatOffset;
75684b2f2278SToby Isaac 
7569d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7570d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
75714b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7572d3d1a6afSToby Isaac 
75739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
75744b2f2278SToby Isaac       if (!bSecDof) {
75754b2f2278SToby Isaac         for (f = 0; f < numFields; f++) {
75764b2f2278SToby Isaac           newPointOffsets[f][p + 1] = 0;
75774b2f2278SToby Isaac           pointMatOffsets[f][p + 1] = 0;
75784b2f2278SToby Isaac         }
75794b2f2278SToby Isaac         continue;
75804b2f2278SToby Isaac       }
758148a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7582d3d1a6afSToby Isaac       if (bDof) {
7583d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7584d3d1a6afSToby Isaac           PetscInt fDof, q, bOff, allFDof = 0;
7585d3d1a6afSToby Isaac 
75869566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
75879566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7588d3d1a6afSToby Isaac           for (q = 0; q < bDof; q++) {
7589d3d1a6afSToby Isaac             PetscInt a = anchors[bOff + q];
7590d3d1a6afSToby Isaac             PetscInt aFDof;
7591d3d1a6afSToby Isaac 
75929566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
7593d3d1a6afSToby Isaac             allFDof += aFDof;
7594d3d1a6afSToby Isaac           }
7595d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = allFDof;
7596d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = fDof * allFDof;
7597d3d1a6afSToby Isaac         }
75989371c9d4SSatish Balay       } else {
7599d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7600d3d1a6afSToby Isaac           PetscInt fDof;
7601d3d1a6afSToby Isaac 
76029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7603d3d1a6afSToby Isaac           newPointOffsets[f][p + 1] = fDof;
7604d3d1a6afSToby Isaac           pointMatOffsets[f][p + 1] = 0;
7605d3d1a6afSToby Isaac         }
7606d3d1a6afSToby Isaac       }
7607d3d1a6afSToby Isaac     }
76084b2f2278SToby Isaac     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
76094b2f2278SToby Isaac       newPointOffsets[f][0] = totalOffset;
76104b2f2278SToby Isaac       pointMatOffsets[f][0] = totalMatOffset;
7611d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7612d3d1a6afSToby Isaac         newPointOffsets[f][p + 1] += newPointOffsets[f][p];
7613d3d1a6afSToby Isaac         pointMatOffsets[f][p + 1] += pointMatOffsets[f][p];
7614d3d1a6afSToby Isaac       }
761519f70fd5SToby Isaac       totalOffset    = newPointOffsets[f][numPoints];
761619f70fd5SToby Isaac       totalMatOffset = pointMatOffsets[f][numPoints];
76179566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7618d3d1a6afSToby Isaac     }
76199371c9d4SSatish Balay   } else {
7620d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7621d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
76224b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7623d3d1a6afSToby Isaac 
76249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
76254b2f2278SToby Isaac       if (!bSecDof) {
76264b2f2278SToby Isaac         newPointOffsets[0][p + 1] = 0;
76274b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = 0;
76284b2f2278SToby Isaac         continue;
76294b2f2278SToby Isaac       }
763048a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7631d3d1a6afSToby Isaac       if (bDof) {
76324b2f2278SToby Isaac         PetscInt bOff, q, allDof = 0;
7633d3d1a6afSToby Isaac 
76349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7635d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7636d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aDof;
7637d3d1a6afSToby Isaac 
76389566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
7639d3d1a6afSToby Isaac           allDof += aDof;
7640d3d1a6afSToby Isaac         }
7641d3d1a6afSToby Isaac         newPointOffsets[0][p + 1] = allDof;
76424b2f2278SToby Isaac         pointMatOffsets[0][p + 1] = bSecDof * allDof;
76439371c9d4SSatish Balay       } else {
76444b2f2278SToby Isaac         newPointOffsets[0][p + 1] = bSecDof;
7645d3d1a6afSToby Isaac         pointMatOffsets[0][p + 1] = 0;
7646d3d1a6afSToby Isaac       }
7647d3d1a6afSToby Isaac     }
7648d3d1a6afSToby Isaac     newPointOffsets[0][0] = 0;
7649d3d1a6afSToby Isaac     pointMatOffsets[0][0] = 0;
7650d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7651d3d1a6afSToby Isaac       newPointOffsets[0][p + 1] += newPointOffsets[0][p];
7652d3d1a6afSToby Isaac       pointMatOffsets[0][p + 1] += pointMatOffsets[0][p];
7653d3d1a6afSToby Isaac     }
76549566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7655d3d1a6afSToby Isaac   }
7656d3d1a6afSToby Isaac 
76576ecaa68aSToby Isaac   /* output arrays */
76589566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
76596ecaa68aSToby Isaac 
7660d3d1a6afSToby Isaac   /* get the point-to-point matrices; construct newPoints */
76619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
76629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
76639566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices));
76649566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7665d3d1a6afSToby Isaac   if (numFields) {
7666d3d1a6afSToby Isaac     for (p = 0, newP = 0; p < numPoints; p++) {
7667d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7668d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
76694b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7670d3d1a6afSToby Isaac 
76719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7672ad540459SPierre Jolivet       if (!bSecDof) continue;
767348a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7674d3d1a6afSToby Isaac       if (bDof) {
7675d3d1a6afSToby Isaac         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
7676d3d1a6afSToby Isaac 
7677d3d1a6afSToby Isaac         fStart[0] = 0;
7678d3d1a6afSToby Isaac         fEnd[0]   = 0;
7679d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7680d3d1a6afSToby Isaac           PetscInt fDof;
7681d3d1a6afSToby Isaac 
76829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7683d3d1a6afSToby Isaac           fStart[f + 1] = fStart[f] + fDof;
7684d3d1a6afSToby Isaac           fEnd[f + 1]   = fStart[f + 1];
7685d3d1a6afSToby Isaac         }
76869566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
76879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
7688d3d1a6afSToby Isaac 
7689d3d1a6afSToby Isaac         fAnchorStart[0] = 0;
7690d3d1a6afSToby Isaac         fAnchorEnd[0]   = 0;
7691d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7692d3d1a6afSToby Isaac           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7693d3d1a6afSToby Isaac 
7694d3d1a6afSToby Isaac           fAnchorStart[f + 1] = fAnchorStart[f] + fDof;
7695d3d1a6afSToby Isaac           fAnchorEnd[f + 1]   = fAnchorStart[f + 1];
7696d3d1a6afSToby Isaac         }
76979566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7698d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7699d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7700d3d1a6afSToby Isaac 
7701d3d1a6afSToby 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 */
7702d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7703d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
77049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
77059566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7706d3d1a6afSToby Isaac         }
7707d3d1a6afSToby Isaac         newP += bDof;
7708d3d1a6afSToby Isaac 
77096ecaa68aSToby Isaac         if (outValues) {
7710d3d1a6afSToby Isaac           /* get the point-to-point submatrix */
771148a46eb9SPierre 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]));
7712d3d1a6afSToby Isaac         }
77139371c9d4SSatish Balay       } else {
7714d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7715d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7716d3d1a6afSToby Isaac         newP++;
7717d3d1a6afSToby Isaac       }
7718d3d1a6afSToby Isaac     }
7719d3d1a6afSToby Isaac   } else {
7720d3d1a6afSToby Isaac     for (p = 0; p < numPoints; p++) {
7721d3d1a6afSToby Isaac       PetscInt b    = points[2 * p];
7722d3d1a6afSToby Isaac       PetscInt o    = points[2 * p + 1];
77234b2f2278SToby Isaac       PetscInt bDof = 0, bSecDof;
7724d3d1a6afSToby Isaac 
77259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7726ad540459SPierre Jolivet       if (!bSecDof) continue;
772748a46eb9SPierre Jolivet       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7728d3d1a6afSToby Isaac       if (bDof) {
7729d3d1a6afSToby Isaac         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7730d3d1a6afSToby Isaac 
77319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
77329566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7733d3d1a6afSToby Isaac 
77349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7735d3d1a6afSToby Isaac         for (q = 0; q < bDof; q++) {
7736d3d1a6afSToby Isaac           PetscInt a = anchors[bOff + q], aOff;
7737d3d1a6afSToby Isaac 
7738d3d1a6afSToby 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 */
7739d3d1a6afSToby Isaac 
7740d3d1a6afSToby Isaac           newPoints[2 * (newP + q)]     = a;
7741d3d1a6afSToby Isaac           newPoints[2 * (newP + q) + 1] = 0;
77429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
77439566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7744d3d1a6afSToby Isaac         }
7745d3d1a6afSToby Isaac         newP += bDof;
7746d3d1a6afSToby Isaac 
7747d3d1a6afSToby Isaac         /* get the point-to-point submatrix */
774848a46eb9SPierre Jolivet         if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p]));
77499371c9d4SSatish Balay       } else {
7750d3d1a6afSToby Isaac         newPoints[2 * newP]     = b;
7751d3d1a6afSToby Isaac         newPoints[2 * newP + 1] = o;
7752d3d1a6afSToby Isaac         newP++;
7753d3d1a6afSToby Isaac       }
7754d3d1a6afSToby Isaac     }
7755d3d1a6afSToby Isaac   }
7756d3d1a6afSToby Isaac 
77576ecaa68aSToby Isaac   if (outValues) {
77589566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
77599566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices));
7760d3d1a6afSToby Isaac     /* multiply constraints on the right */
7761d3d1a6afSToby Isaac     if (numFields) {
7762d3d1a6afSToby Isaac       for (f = 0; f < numFields; f++) {
7763d3d1a6afSToby Isaac         PetscInt oldOff = offsets[f];
7764d3d1a6afSToby Isaac 
7765d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7766d3d1a6afSToby Isaac           PetscInt cStart = newPointOffsets[f][p];
7767d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7768d3d1a6afSToby Isaac           PetscInt c, r, k;
7769d3d1a6afSToby Isaac           PetscInt dof;
7770d3d1a6afSToby Isaac 
77719566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7772ad540459SPierre Jolivet           if (!dof) continue;
7773d3d1a6afSToby Isaac           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7774d3d1a6afSToby Isaac             PetscInt           nCols = newPointOffsets[f][p + 1] - cStart;
7775d3d1a6afSToby Isaac             const PetscScalar *mat   = pointMat[f] + pointMatOffsets[f][p];
7776d3d1a6afSToby Isaac 
7777d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7778d3d1a6afSToby Isaac               for (c = 0; c < nCols; c++) {
7779ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7780d3d1a6afSToby Isaac               }
7781d3d1a6afSToby Isaac             }
77829371c9d4SSatish Balay           } else {
7783d3d1a6afSToby Isaac             /* copy this column as is */
7784d3d1a6afSToby Isaac             for (r = 0; r < numIndices; r++) {
7785ad540459SPierre Jolivet               for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7786d3d1a6afSToby Isaac             }
7787d3d1a6afSToby Isaac           }
7788d3d1a6afSToby Isaac           oldOff += dof;
7789d3d1a6afSToby Isaac         }
7790d3d1a6afSToby Isaac       }
77919371c9d4SSatish Balay     } else {
7792d3d1a6afSToby Isaac       PetscInt oldOff = 0;
7793d3d1a6afSToby Isaac       for (p = 0; p < numPoints; p++) {
7794d3d1a6afSToby Isaac         PetscInt cStart = newPointOffsets[0][p];
7795d3d1a6afSToby Isaac         PetscInt b      = points[2 * p];
7796d3d1a6afSToby Isaac         PetscInt c, r, k;
7797d3d1a6afSToby Isaac         PetscInt dof;
7798d3d1a6afSToby Isaac 
77999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, b, &dof));
7800ad540459SPierre Jolivet         if (!dof) continue;
7801d3d1a6afSToby Isaac         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7802d3d1a6afSToby Isaac           PetscInt           nCols = newPointOffsets[0][p + 1] - cStart;
7803d3d1a6afSToby Isaac           const PetscScalar *mat   = pointMat[0] + pointMatOffsets[0][p];
7804d3d1a6afSToby Isaac 
7805d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7806d3d1a6afSToby Isaac             for (c = 0; c < nCols; c++) {
7807ad540459SPierre Jolivet               for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7808d3d1a6afSToby Isaac             }
7809d3d1a6afSToby Isaac           }
78109371c9d4SSatish Balay         } else {
7811d3d1a6afSToby Isaac           /* copy this column as is */
7812d3d1a6afSToby Isaac           for (r = 0; r < numIndices; r++) {
7813ad540459SPierre Jolivet             for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7814d3d1a6afSToby Isaac           }
7815d3d1a6afSToby Isaac         }
7816d3d1a6afSToby Isaac         oldOff += dof;
7817d3d1a6afSToby Isaac       }
7818d3d1a6afSToby Isaac     }
7819d3d1a6afSToby Isaac 
78206ecaa68aSToby Isaac     if (multiplyLeft) {
78219566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues));
78229566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices));
7823d3d1a6afSToby Isaac       /* multiply constraints transpose on the left */
7824d3d1a6afSToby Isaac       if (numFields) {
7825d3d1a6afSToby Isaac         for (f = 0; f < numFields; f++) {
7826d3d1a6afSToby Isaac           PetscInt oldOff = offsets[f];
7827d3d1a6afSToby Isaac 
7828d3d1a6afSToby Isaac           for (p = 0; p < numPoints; p++) {
7829d3d1a6afSToby Isaac             PetscInt rStart = newPointOffsets[f][p];
7830d3d1a6afSToby Isaac             PetscInt b      = points[2 * p];
7831d3d1a6afSToby Isaac             PetscInt c, r, k;
7832d3d1a6afSToby Isaac             PetscInt dof;
7833d3d1a6afSToby Isaac 
78349566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7835d3d1a6afSToby Isaac             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7836d3d1a6afSToby Isaac               PetscInt                          nRows = newPointOffsets[f][p + 1] - rStart;
7837d3d1a6afSToby Isaac               const PetscScalar *PETSC_RESTRICT mat   = pointMat[f] + pointMatOffsets[f][p];
7838d3d1a6afSToby Isaac 
7839d3d1a6afSToby Isaac               for (r = 0; r < nRows; r++) {
7840d3d1a6afSToby Isaac                 for (c = 0; c < newNumIndices; c++) {
7841ad540459SPierre Jolivet                   for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7842d3d1a6afSToby Isaac                 }
7843d3d1a6afSToby Isaac               }
78449371c9d4SSatish Balay             } else {
7845d3d1a6afSToby Isaac               /* copy this row as is */
7846d3d1a6afSToby Isaac               for (r = 0; r < dof; r++) {
7847ad540459SPierre Jolivet                 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7848d3d1a6afSToby Isaac               }
7849d3d1a6afSToby Isaac             }
7850d3d1a6afSToby Isaac             oldOff += dof;
7851d3d1a6afSToby Isaac           }
7852d3d1a6afSToby Isaac         }
78539371c9d4SSatish Balay       } else {
7854d3d1a6afSToby Isaac         PetscInt oldOff = 0;
7855d3d1a6afSToby Isaac 
7856d3d1a6afSToby Isaac         for (p = 0; p < numPoints; p++) {
7857d3d1a6afSToby Isaac           PetscInt rStart = newPointOffsets[0][p];
7858d3d1a6afSToby Isaac           PetscInt b      = points[2 * p];
7859d3d1a6afSToby Isaac           PetscInt c, r, k;
7860d3d1a6afSToby Isaac           PetscInt dof;
7861d3d1a6afSToby Isaac 
78629566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, b, &dof));
7863d3d1a6afSToby Isaac           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7864d3d1a6afSToby Isaac             PetscInt                          nRows = newPointOffsets[0][p + 1] - rStart;
7865d3d1a6afSToby Isaac             const PetscScalar *PETSC_RESTRICT mat   = pointMat[0] + pointMatOffsets[0][p];
7866d3d1a6afSToby Isaac 
7867d3d1a6afSToby Isaac             for (r = 0; r < nRows; r++) {
7868d3d1a6afSToby Isaac               for (c = 0; c < newNumIndices; c++) {
7869ad540459SPierre Jolivet                 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7870d3d1a6afSToby Isaac               }
7871d3d1a6afSToby Isaac             }
78729371c9d4SSatish Balay           } else {
7873d3d1a6afSToby Isaac             /* copy this row as is */
78749fc93327SToby Isaac             for (r = 0; r < dof; r++) {
7875ad540459SPierre Jolivet               for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7876d3d1a6afSToby Isaac             }
7877d3d1a6afSToby Isaac           }
7878d3d1a6afSToby Isaac           oldOff += dof;
7879d3d1a6afSToby Isaac         }
7880d3d1a6afSToby Isaac       }
7881d3d1a6afSToby Isaac 
78829566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
78839371c9d4SSatish Balay     } else {
78846ecaa68aSToby Isaac       newValues = tmpValues;
78856ecaa68aSToby Isaac     }
78866ecaa68aSToby Isaac   }
78876ecaa68aSToby Isaac 
7888d3d1a6afSToby Isaac   /* clean up */
78899566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices));
78909566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
78916ecaa68aSToby Isaac 
7892d3d1a6afSToby Isaac   if (numFields) {
7893d3d1a6afSToby Isaac     for (f = 0; f < numFields; f++) {
78949566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
78959566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
78969566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7897d3d1a6afSToby Isaac     }
78989371c9d4SSatish Balay   } else {
78999566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
79009566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
79019566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0]));
7902d3d1a6afSToby Isaac   }
79039566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
7904d3d1a6afSToby Isaac 
7905d3d1a6afSToby Isaac   /* output */
79066ecaa68aSToby Isaac   if (outPoints) {
7907d3d1a6afSToby Isaac     *outPoints = newPoints;
79089371c9d4SSatish Balay   } else {
79099566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
79106ecaa68aSToby Isaac   }
7911ad540459SPierre Jolivet   if (outValues) *outValues = newValues;
7912ad540459SPierre Jolivet   for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
79133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7914d3d1a6afSToby Isaac }
7915d3d1a6afSToby Isaac 
79164a1e0b3eSMatthew G. Knepley /*@C
791771f0bbf9SMatthew G. Knepley   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
79187cd05799SMatthew G. Knepley 
79197cd05799SMatthew G. Knepley   Not collective
79207cd05799SMatthew G. Knepley 
79217cd05799SMatthew G. Knepley   Input Parameters:
7922a1cb98faSBarry Smith + dm         - The `DM`
7923a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
7924a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
792571f0bbf9SMatthew G. Knepley . point      - The point defining the closure
792671f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
79277cd05799SMatthew G. Knepley 
792871f0bbf9SMatthew G. Knepley   Output Parameters:
792971f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
793071f0bbf9SMatthew G. Knepley . indices    - The dof indices
793120f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
793220f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
79337cd05799SMatthew G. Knepley 
7934a1cb98faSBarry Smith   Level: advanced
793536fa2b79SJed Brown 
7936a1cb98faSBarry Smith   Notes:
7937a1cb98faSBarry Smith   Must call `DMPlexRestoreClosureIndices()` to free allocated memory
7938a1cb98faSBarry Smith 
793920f4b53cSBarry Smith   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
794020f4b53cSBarry Smith   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
794136fa2b79SJed Brown   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
794220f4b53cSBarry Smith   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
794336fa2b79SJed Brown   indices (with the above semantics) are implied.
79447cd05799SMatthew G. Knepley 
79451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
7946a1cb98faSBarry Smith           `PetscSection`, `DMGetGlobalSection()`
79474a1e0b3eSMatthew G. Knepley @*/
7948d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7949d71ae5a4SJacob Faibussowitsch {
795071f0bbf9SMatthew G. Knepley   /* Closure ordering */
79517773e69fSMatthew G. Knepley   PetscSection    clSection;
79527773e69fSMatthew G. Knepley   IS              clPoints;
795371f0bbf9SMatthew G. Knepley   const PetscInt *clp;
795471f0bbf9SMatthew G. Knepley   PetscInt       *points;
795571f0bbf9SMatthew G. Knepley   const PetscInt *clperm = NULL;
795671f0bbf9SMatthew G. Knepley   /* Dof permutation and sign flips */
79574acb8e1eSToby Isaac   const PetscInt    **perms[32] = {NULL};
795871f0bbf9SMatthew G. Knepley   const PetscScalar **flips[32] = {NULL};
795971f0bbf9SMatthew G. Knepley   PetscScalar        *valCopy   = NULL;
796071f0bbf9SMatthew G. Knepley   /* Hanging node constraints */
796171f0bbf9SMatthew G. Knepley   PetscInt    *pointsC = NULL;
796271f0bbf9SMatthew G. Knepley   PetscScalar *valuesC = NULL;
796371f0bbf9SMatthew G. Knepley   PetscInt     NclC, NiC;
796471f0bbf9SMatthew G. Knepley 
796571f0bbf9SMatthew G. Knepley   PetscInt *idx;
796671f0bbf9SMatthew G. Knepley   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
796771f0bbf9SMatthew G. Knepley   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
79687773e69fSMatthew G. Knepley 
796971f0bbf9SMatthew G. Knepley   PetscFunctionBeginHot;
79707773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
79717773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
797236fa2b79SJed Brown   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
79734f572ea9SToby Isaac   if (numIndices) PetscAssertPointer(numIndices, 6);
79744f572ea9SToby Isaac   if (indices) PetscAssertPointer(indices, 7);
79754f572ea9SToby Isaac   if (outOffsets) PetscAssertPointer(outOffsets, 8);
79764f572ea9SToby Isaac   if (values) PetscAssertPointer(values, 9);
79779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
797863a3b9bcSJacob Faibussowitsch   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
79799566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(offsets, 32));
798071f0bbf9SMatthew G. Knepley   /* 1) Get points in closure */
798107218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7982c459fbc1SJed Brown   if (useClPerm) {
7983c459fbc1SJed Brown     PetscInt depth, clsize;
79849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7985c459fbc1SJed Brown     for (clsize = 0, p = 0; p < Ncl; p++) {
7986c459fbc1SJed Brown       PetscInt dof;
79879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7988c459fbc1SJed Brown       clsize += dof;
7989c459fbc1SJed Brown     }
79909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7991c459fbc1SJed Brown   }
799271f0bbf9SMatthew G. Knepley   /* 2) Get number of indices on these points and field offsets from section */
799371f0bbf9SMatthew G. Knepley   for (p = 0; p < Ncl * 2; p += 2) {
79947773e69fSMatthew G. Knepley     PetscInt dof, fdof;
79957773e69fSMatthew G. Knepley 
79969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, points[p], &dof));
79977773e69fSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
79989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
79997773e69fSMatthew G. Knepley       offsets[f + 1] += fdof;
80007773e69fSMatthew G. Knepley     }
800171f0bbf9SMatthew G. Knepley     Ni += dof;
80027773e69fSMatthew G. Knepley   }
80037773e69fSMatthew G. Knepley   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
80041dca8a05SBarry 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);
800571f0bbf9SMatthew G. Knepley   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
800671f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
80079566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
80089566063dSJacob Faibussowitsch     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
800971f0bbf9SMatthew G. Knepley     /* may need to apply sign changes to the element matrix */
801071f0bbf9SMatthew G. Knepley     if (values && flips[f]) {
801171f0bbf9SMatthew G. Knepley       PetscInt foffset = offsets[f];
80126ecaa68aSToby Isaac 
801371f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
801471f0bbf9SMatthew G. Knepley         PetscInt           pnt  = points[2 * p], fdof;
801571f0bbf9SMatthew G. Knepley         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
801671f0bbf9SMatthew G. Knepley 
80179566063dSJacob Faibussowitsch         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
80189566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
801971f0bbf9SMatthew G. Knepley         if (flip) {
802071f0bbf9SMatthew G. Knepley           PetscInt i, j, k;
802171f0bbf9SMatthew G. Knepley 
802271f0bbf9SMatthew G. Knepley           if (!valCopy) {
80239566063dSJacob Faibussowitsch             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
802471f0bbf9SMatthew G. Knepley             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
802571f0bbf9SMatthew G. Knepley             *values = valCopy;
802671f0bbf9SMatthew G. Knepley           }
802771f0bbf9SMatthew G. Knepley           for (i = 0; i < fdof; ++i) {
802871f0bbf9SMatthew G. Knepley             PetscScalar fval = flip[i];
802971f0bbf9SMatthew G. Knepley 
803071f0bbf9SMatthew G. Knepley             for (k = 0; k < Ni; ++k) {
803171f0bbf9SMatthew G. Knepley               valCopy[Ni * (foffset + i) + k] *= fval;
803271f0bbf9SMatthew G. Knepley               valCopy[Ni * k + (foffset + i)] *= fval;
80336ecaa68aSToby Isaac             }
80346ecaa68aSToby Isaac           }
803571f0bbf9SMatthew G. Knepley         }
803671f0bbf9SMatthew G. Knepley         foffset += fdof;
803771f0bbf9SMatthew G. Knepley       }
803871f0bbf9SMatthew G. Knepley     }
803971f0bbf9SMatthew G. Knepley   }
804071f0bbf9SMatthew G. Knepley   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
80419566063dSJacob Faibussowitsch   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
804271f0bbf9SMatthew G. Knepley   if (NclC) {
80439566063dSJacob Faibussowitsch     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
804471f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
80459566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
80469566063dSJacob Faibussowitsch       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
804771f0bbf9SMatthew G. Knepley     }
804871f0bbf9SMatthew G. Knepley     for (f = 0; f < PetscMax(1, Nf); ++f) {
80499566063dSJacob Faibussowitsch       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
80509566063dSJacob Faibussowitsch       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
805171f0bbf9SMatthew G. Knepley     }
80529566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
805371f0bbf9SMatthew G. Knepley     Ncl    = NclC;
805471f0bbf9SMatthew G. Knepley     Ni     = NiC;
805571f0bbf9SMatthew G. Knepley     points = pointsC;
805671f0bbf9SMatthew G. Knepley     if (values) *values = valuesC;
805771f0bbf9SMatthew G. Knepley   }
805871f0bbf9SMatthew G. Knepley   /* 5) Calculate indices */
80599566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
806071f0bbf9SMatthew G. Knepley   if (Nf) {
806171f0bbf9SMatthew G. Knepley     PetscInt  idxOff;
806271f0bbf9SMatthew G. Knepley     PetscBool useFieldOffsets;
806371f0bbf9SMatthew G. Knepley 
80649371c9d4SSatish Balay     if (outOffsets) {
80659371c9d4SSatish Balay       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
80669371c9d4SSatish Balay     }
80679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
806871f0bbf9SMatthew G. Knepley     if (useFieldOffsets) {
806971f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
807071f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
807171f0bbf9SMatthew G. Knepley 
80729566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
80737773e69fSMatthew G. Knepley       }
80747773e69fSMatthew G. Knepley     } else {
807571f0bbf9SMatthew G. Knepley       for (p = 0; p < Ncl; ++p) {
807671f0bbf9SMatthew G. Knepley         const PetscInt pnt = points[p * 2];
807771f0bbf9SMatthew G. Knepley 
80789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
807971f0bbf9SMatthew G. Knepley         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
808071f0bbf9SMatthew G. Knepley          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
808171f0bbf9SMatthew G. Knepley          * global section. */
80829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
808371f0bbf9SMatthew G. Knepley       }
808471f0bbf9SMatthew G. Knepley     }
808571f0bbf9SMatthew G. Knepley   } else {
808671f0bbf9SMatthew G. Knepley     PetscInt off = 0, idxOff;
808771f0bbf9SMatthew G. Knepley 
808871f0bbf9SMatthew G. Knepley     for (p = 0; p < Ncl; ++p) {
808971f0bbf9SMatthew G. Knepley       const PetscInt  pnt  = points[p * 2];
80904acb8e1eSToby Isaac       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
80914acb8e1eSToby Isaac 
80929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
809371f0bbf9SMatthew G. Knepley       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
809471f0bbf9SMatthew G. Knepley        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
80959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
80967773e69fSMatthew G. Knepley     }
80977773e69fSMatthew G. Knepley   }
809871f0bbf9SMatthew G. Knepley   /* 6) Cleanup */
809971f0bbf9SMatthew G. Knepley   for (f = 0; f < PetscMax(1, Nf); ++f) {
81009566063dSJacob Faibussowitsch     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
81019566063dSJacob Faibussowitsch     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
81024acb8e1eSToby Isaac   }
810371f0bbf9SMatthew G. Knepley   if (NclC) {
81049566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
81057773e69fSMatthew G. Knepley   } else {
81069566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
81077773e69fSMatthew G. Knepley   }
810871f0bbf9SMatthew G. Knepley 
810971f0bbf9SMatthew G. Knepley   if (numIndices) *numIndices = Ni;
811071f0bbf9SMatthew G. Knepley   if (indices) *indices = idx;
81113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81127773e69fSMatthew G. Knepley }
81137773e69fSMatthew G. Knepley 
81147cd05799SMatthew G. Knepley /*@C
811571f0bbf9SMatthew G. Knepley   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
81167cd05799SMatthew G. Knepley 
81177cd05799SMatthew G. Knepley   Not collective
81187cd05799SMatthew G. Knepley 
81197cd05799SMatthew G. Knepley   Input Parameters:
8120a1cb98faSBarry Smith + dm         - The `DM`
8121a1cb98faSBarry Smith . section    - The `PetscSection` describing the points (a local section)
8122a1cb98faSBarry Smith . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
812371f0bbf9SMatthew G. Knepley . point      - The point defining the closure
812471f0bbf9SMatthew G. Knepley - useClPerm  - Use the closure point permutation if available
812571f0bbf9SMatthew G. Knepley 
812671f0bbf9SMatthew G. Knepley   Output Parameters:
812771f0bbf9SMatthew G. Knepley + numIndices - The number of dof indices in the closure of point with the input sections
812871f0bbf9SMatthew G. Knepley . indices    - The dof indices
812920f4b53cSBarry Smith . outOffsets - Array to write the field offsets into, or `NULL`
813020f4b53cSBarry Smith - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
813171f0bbf9SMatthew G. Knepley 
8132a1cb98faSBarry Smith   Level: advanced
813371f0bbf9SMatthew G. Knepley 
8134a1cb98faSBarry Smith   Notes:
8135a1cb98faSBarry Smith   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
8136a1cb98faSBarry Smith 
8137a1cb98faSBarry Smith   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
813871f0bbf9SMatthew G. Knepley   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
813971f0bbf9SMatthew G. Knepley   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
814071f0bbf9SMatthew G. Knepley   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
814171f0bbf9SMatthew G. Knepley   indices (with the above semantics) are implied.
81427cd05799SMatthew G. Knepley 
81431cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
81447cd05799SMatthew G. Knepley @*/
8145d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
8146d71ae5a4SJacob Faibussowitsch {
81477773e69fSMatthew G. Knepley   PetscFunctionBegin;
81487773e69fSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81494f572ea9SToby Isaac   PetscAssertPointer(indices, 7);
81509566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
81513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81527773e69fSMatthew G. Knepley }
81537773e69fSMatthew G. Knepley 
8154e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8155d71ae5a4SJacob Faibussowitsch {
8156552f7358SJed Brown   DM_Plex           *mesh = (DM_Plex *)dm->data;
8157552f7358SJed Brown   PetscInt          *indices;
815871f0bbf9SMatthew G. Knepley   PetscInt           numIndices;
815971f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
8160552f7358SJed Brown   PetscErrorCode     ierr;
8161552f7358SJed Brown 
8162552f7358SJed Brown   PetscFunctionBegin;
8163552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81649566063dSJacob Faibussowitsch   if (!section) PetscCall(DMGetLocalSection(dm, &section));
81653dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
81669566063dSJacob Faibussowitsch   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
81673dc93601SMatthew G. Knepley   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
8168e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 5);
8169552f7358SJed Brown 
8170e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
81710d644c17SKarl Rupp 
81729566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
8173d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
81744a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8175552f7358SJed Brown   if (ierr) {
8176552f7358SJed Brown     PetscMPIInt rank;
8177552f7358SJed Brown 
81789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
81799566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
81809566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
81819566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
81829566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
8183c3e24edfSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
8184552f7358SJed Brown   }
81854a1e0b3eSMatthew G. Knepley   if (mesh->printFEM > 1) {
81864a1e0b3eSMatthew G. Knepley     PetscInt i;
81879566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
818863a3b9bcSJacob Faibussowitsch     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
81899566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
81904a1e0b3eSMatthew G. Knepley   }
819171f0bbf9SMatthew G. Knepley 
81929566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
81939566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
81943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81954acb8e1eSToby Isaac }
819671f0bbf9SMatthew G. Knepley 
81974a1e0b3eSMatthew G. Knepley /*@C
8198e8e188d2SZach Atkins   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
8199e8e188d2SZach Atkins 
8200e8e188d2SZach Atkins   Not collective
8201e8e188d2SZach Atkins 
8202e8e188d2SZach Atkins   Input Parameters:
8203e8e188d2SZach Atkins + dm            - The `DM`
8204e8e188d2SZach Atkins . section       - The section describing the layout in `v`, or `NULL` to use the default section
8205e8e188d2SZach Atkins . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
8206e8e188d2SZach Atkins . A             - The matrix
8207e8e188d2SZach Atkins . point         - The point in the `DM`
8208e8e188d2SZach Atkins . values        - The array of values
8209e8e188d2SZach Atkins - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
8210e8e188d2SZach Atkins 
8211e8e188d2SZach Atkins   Level: intermediate
8212e8e188d2SZach Atkins 
8213e8e188d2SZach Atkins .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
8214e8e188d2SZach Atkins @*/
8215e8e188d2SZach Atkins PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8216e8e188d2SZach Atkins {
8217e8e188d2SZach Atkins   PetscFunctionBegin;
8218e8e188d2SZach Atkins   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
8219e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
8220e8e188d2SZach Atkins }
8221e8e188d2SZach Atkins 
8222e8e188d2SZach Atkins /*@C
822360225df5SJacob Faibussowitsch   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
82244a1e0b3eSMatthew G. Knepley 
82254a1e0b3eSMatthew G. Knepley   Not collective
82264a1e0b3eSMatthew G. Knepley 
82274a1e0b3eSMatthew G. Knepley   Input Parameters:
8228a1cb98faSBarry Smith + dmRow            - The `DM` for the row fields
822920f4b53cSBarry Smith . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
8230e8e188d2SZach Atkins . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
823120f4b53cSBarry Smith . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
8232a1cb98faSBarry Smith . dmCol            - The `DM` for the column fields
823320f4b53cSBarry Smith . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
8234e8e188d2SZach Atkins . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
823520f4b53cSBarry Smith . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
82364a1e0b3eSMatthew G. Knepley . A                - The matrix
8237a1cb98faSBarry Smith . point            - The point in the `DM`
82384a1e0b3eSMatthew G. Knepley . values           - The array of values
8239a1cb98faSBarry Smith - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
82404a1e0b3eSMatthew G. Knepley 
82414a1e0b3eSMatthew G. Knepley   Level: intermediate
82424a1e0b3eSMatthew G. Knepley 
82431cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
82444a1e0b3eSMatthew G. Knepley @*/
8245e8e188d2SZach 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)
8246d71ae5a4SJacob Faibussowitsch {
824771f0bbf9SMatthew G. Knepley   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
824871f0bbf9SMatthew G. Knepley   PetscInt          *indicesRow, *indicesCol;
824971f0bbf9SMatthew G. Knepley   PetscInt           numIndicesRow, numIndicesCol;
825071f0bbf9SMatthew G. Knepley   const PetscScalar *valuesOrig = values;
825171f0bbf9SMatthew G. Knepley   PetscErrorCode     ierr;
825271f0bbf9SMatthew G. Knepley 
825371f0bbf9SMatthew G. Knepley   PetscFunctionBegin;
825471f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
82559566063dSJacob Faibussowitsch   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
825671f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
82579566063dSJacob Faibussowitsch   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
825871f0bbf9SMatthew G. Knepley   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
8259e8e188d2SZach Atkins   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5);
82609566063dSJacob Faibussowitsch   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
8261e8e188d2SZach Atkins   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6);
82629566063dSJacob Faibussowitsch   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
8263e8e188d2SZach Atkins   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7);
8264e8e188d2SZach Atkins   PetscValidHeaderSpecific(A, MAT_CLASSID, 9);
826571f0bbf9SMatthew G. Knepley 
8266e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
8267e8e188d2SZach Atkins   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
826871f0bbf9SMatthew G. Knepley 
82699566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
8270d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
82714a1e0b3eSMatthew G. Knepley   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
827271f0bbf9SMatthew G. Knepley   if (ierr) {
827371f0bbf9SMatthew G. Knepley     PetscMPIInt rank;
827471f0bbf9SMatthew G. Knepley 
82759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
82769566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
82779566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
82789566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
82799566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values));
82809566063dSJacob Faibussowitsch     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
8281d3d1a6afSToby Isaac   }
828271f0bbf9SMatthew G. Knepley 
8283e8e188d2SZach Atkins   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
8284e8e188d2SZach Atkins   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
82859566063dSJacob Faibussowitsch   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
82863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8287552f7358SJed Brown }
8288552f7358SJed Brown 
8289d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
8290d71ae5a4SJacob Faibussowitsch {
8291de41b84cSMatthew G. Knepley   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
8292de41b84cSMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
8293de41b84cSMatthew G. Knepley   PetscInt       *cpoints = NULL;
8294de41b84cSMatthew G. Knepley   PetscInt       *findices, *cindices;
829517c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8296de41b84cSMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
8297412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
82984ca5e9f5SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8299de41b84cSMatthew G. Knepley   PetscErrorCode  ierr;
8300de41b84cSMatthew G. Knepley 
8301de41b84cSMatthew G. Knepley   PetscFunctionBegin;
8302de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
8303de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
83049566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8305de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
83069566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8307de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
83089566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
8309de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
83109566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
8311de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
8312de41b84cSMatthew G. Knepley   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
83139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
831463a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
83159566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
83169566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
8317de41b84cSMatthew G. Knepley   /* Column indices */
83189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
83194ca5e9f5SMatthew G. Knepley   maxFPoints = numCPoints;
8320de41b84cSMatthew G. Knepley   /* Compress out points not in the section */
8321de41b84cSMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
83229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
8323de41b84cSMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
8324de41b84cSMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
8325de41b84cSMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
8326de41b84cSMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
8327de41b84cSMatthew G. Knepley       ++q;
8328de41b84cSMatthew G. Knepley     }
8329de41b84cSMatthew G. Knepley   }
8330de41b84cSMatthew G. Knepley   numCPoints = q;
8331de41b84cSMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
8332de41b84cSMatthew G. Knepley     PetscInt fdof;
8333de41b84cSMatthew G. Knepley 
83349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
83354ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8336de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
83379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
8338de41b84cSMatthew G. Knepley       coffsets[f + 1] += fdof;
8339de41b84cSMatthew G. Knepley     }
8340de41b84cSMatthew G. Knepley     numCIndices += dof;
8341de41b84cSMatthew G. Knepley   }
8342de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
8343de41b84cSMatthew G. Knepley   /* Row indices */
83449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8345412e9a14SMatthew G. Knepley   {
8346012bc364SMatthew G. Knepley     DMPlexTransform tr;
8347012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8348012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8349012bc364SMatthew G. Knepley 
83509566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
83519566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
83529566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8353012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
83549566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8355412e9a14SMatthew G. Knepley   }
83569566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
8357de41b84cSMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
8358de41b84cSMatthew G. Knepley     /* TODO Map from coarse to fine cells */
83599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
8360de41b84cSMatthew G. Knepley     /* Compress out points not in the section */
83619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
8362de41b84cSMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
8363de41b84cSMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
83649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
83654ca5e9f5SMatthew G. Knepley         if (!dof) continue;
83669371c9d4SSatish Balay         for (s = 0; s < q; ++s)
83679371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
83684ca5e9f5SMatthew G. Knepley         if (s < q) continue;
8369de41b84cSMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
8370de41b84cSMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
8371de41b84cSMatthew G. Knepley         ++q;
8372de41b84cSMatthew G. Knepley       }
8373de41b84cSMatthew G. Knepley     }
83749566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
8375de41b84cSMatthew G. Knepley   }
8376de41b84cSMatthew G. Knepley   numFPoints = q;
8377de41b84cSMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
8378de41b84cSMatthew G. Knepley     PetscInt fdof;
8379de41b84cSMatthew G. Knepley 
83809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
83814ca5e9f5SMatthew G. Knepley     if (!dof) continue;
8382de41b84cSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
83839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
8384de41b84cSMatthew G. Knepley       foffsets[f + 1] += fdof;
8385de41b84cSMatthew G. Knepley     }
8386de41b84cSMatthew G. Knepley     numFIndices += dof;
8387de41b84cSMatthew G. Knepley   }
8388de41b84cSMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
8389de41b84cSMatthew G. Knepley 
83901dca8a05SBarry 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);
83911dca8a05SBarry 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);
83929566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices));
83939566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8394de41b84cSMatthew G. Knepley   if (numFields) {
83954acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
83964acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
83974acb8e1eSToby Isaac 
83984acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
83999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
84009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8401de41b84cSMatthew G. Knepley     }
84024acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
84039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
84049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
84054acb8e1eSToby Isaac     }
84064acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
84079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
84089566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
84094acb8e1eSToby Isaac     }
84104acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
84119566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
84129566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
8413de41b84cSMatthew G. Knepley     }
8414de41b84cSMatthew G. Knepley   } else {
84154acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
84164acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
84174acb8e1eSToby Isaac 
84189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
84199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
84204acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
84214acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
84224acb8e1eSToby Isaac 
84239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
84249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
8425de41b84cSMatthew G. Knepley     }
84264acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
84274acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
84284acb8e1eSToby Isaac 
84299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
84309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
8431de41b84cSMatthew G. Knepley     }
84329566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
84339566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
8434de41b84cSMatthew G. Knepley   }
84359566063dSJacob Faibussowitsch   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
84364acb8e1eSToby Isaac   /* TODO: flips */
8437d0609cedSBarry Smith   /* TODO: fix this code to not use error codes as handle-able exceptions! */
8438de41b84cSMatthew G. Knepley   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
8439de41b84cSMatthew G. Knepley   if (ierr) {
8440de41b84cSMatthew G. Knepley     PetscMPIInt rank;
8441de41b84cSMatthew G. Knepley 
84429566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
84439566063dSJacob Faibussowitsch     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
84449566063dSJacob Faibussowitsch     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values));
84459566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
84469566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
8447de41b84cSMatthew G. Knepley   }
84489566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
84499566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
84509566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices));
84519566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices));
84523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8453de41b84cSMatthew G. Knepley }
8454de41b84cSMatthew G. Knepley 
8455d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
8456d71ae5a4SJacob Faibussowitsch {
84577c927364SMatthew G. Knepley   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
84587c927364SMatthew G. Knepley   PetscInt       *cpoints = NULL;
84597c927364SMatthew G. Knepley   PetscInt        foffsets[32], coffsets[32];
846017c0192bSMatthew G. Knepley   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
8461412e9a14SMatthew G. Knepley   DMPolytopeType  ct;
84627c927364SMatthew G. Knepley   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
84637c927364SMatthew G. Knepley 
84647c927364SMatthew G. Knepley   PetscFunctionBegin;
84657c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
84667c927364SMatthew G. Knepley   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
84679566063dSJacob Faibussowitsch   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
84687c927364SMatthew G. Knepley   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
84699566063dSJacob Faibussowitsch   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
84707c927364SMatthew G. Knepley   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
84719566063dSJacob Faibussowitsch   if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection));
84727c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
84739566063dSJacob Faibussowitsch   if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection));
84747c927364SMatthew G. Knepley   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
84759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &numFields));
847663a3b9bcSJacob Faibussowitsch   PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields);
84779566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(foffsets, 32));
84789566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coffsets, 32));
84797c927364SMatthew G. Knepley   /* Column indices */
84809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
84817c927364SMatthew G. Knepley   maxFPoints = numCPoints;
84827c927364SMatthew G. Knepley   /* Compress out points not in the section */
84837c927364SMatthew G. Knepley   /*   TODO: Squeeze out points with 0 dof as well */
84849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd));
84857c927364SMatthew G. Knepley   for (p = 0, q = 0; p < numCPoints * 2; p += 2) {
84867c927364SMatthew G. Knepley     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
84877c927364SMatthew G. Knepley       cpoints[q * 2]     = cpoints[p];
84887c927364SMatthew G. Knepley       cpoints[q * 2 + 1] = cpoints[p + 1];
84897c927364SMatthew G. Knepley       ++q;
84907c927364SMatthew G. Knepley     }
84917c927364SMatthew G. Knepley   }
84927c927364SMatthew G. Knepley   numCPoints = q;
84937c927364SMatthew G. Knepley   for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) {
84947c927364SMatthew G. Knepley     PetscInt fdof;
84957c927364SMatthew G. Knepley 
84969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof));
84977c927364SMatthew G. Knepley     if (!dof) continue;
84987c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
84999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof));
85007c927364SMatthew G. Knepley       coffsets[f + 1] += fdof;
85017c927364SMatthew G. Knepley     }
85027c927364SMatthew G. Knepley     numCIndices += dof;
85037c927364SMatthew G. Knepley   }
85047c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f];
85057c927364SMatthew G. Knepley   /* Row indices */
85069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dmc, point, &ct));
8507412e9a14SMatthew G. Knepley   {
8508012bc364SMatthew G. Knepley     DMPlexTransform tr;
8509012bc364SMatthew G. Knepley     DMPolytopeType *rct;
8510012bc364SMatthew G. Knepley     PetscInt       *rsize, *rcone, *rornt, Nt;
8511012bc364SMatthew G. Knepley 
85129566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
85139566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
85149566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
8515012bc364SMatthew G. Knepley     numSubcells = rsize[Nt - 1];
85169566063dSJacob Faibussowitsch     PetscCall(DMPlexTransformDestroy(&tr));
8517412e9a14SMatthew G. Knepley   }
85189566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints));
85197c927364SMatthew G. Knepley   for (r = 0, q = 0; r < numSubcells; ++r) {
85207c927364SMatthew G. Knepley     /* TODO Map from coarse to fine cells */
85219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints));
85227c927364SMatthew G. Knepley     /* Compress out points not in the section */
85239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd));
85247c927364SMatthew G. Knepley     for (p = 0; p < numFPoints * 2; p += 2) {
85257c927364SMatthew G. Knepley       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
85269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof));
85277c927364SMatthew G. Knepley         if (!dof) continue;
85289371c9d4SSatish Balay         for (s = 0; s < q; ++s)
85299371c9d4SSatish Balay           if (fpoints[p] == ftotpoints[s * 2]) break;
85307c927364SMatthew G. Knepley         if (s < q) continue;
85317c927364SMatthew G. Knepley         ftotpoints[q * 2]     = fpoints[p];
85327c927364SMatthew G. Knepley         ftotpoints[q * 2 + 1] = fpoints[p + 1];
85337c927364SMatthew G. Knepley         ++q;
85347c927364SMatthew G. Knepley       }
85357c927364SMatthew G. Knepley     }
85369566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints));
85377c927364SMatthew G. Knepley   }
85387c927364SMatthew G. Knepley   numFPoints = q;
85397c927364SMatthew G. Knepley   for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) {
85407c927364SMatthew G. Knepley     PetscInt fdof;
85417c927364SMatthew G. Knepley 
85429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof));
85437c927364SMatthew G. Knepley     if (!dof) continue;
85447c927364SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
85459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof));
85467c927364SMatthew G. Knepley       foffsets[f + 1] += fdof;
85477c927364SMatthew G. Knepley     }
85487c927364SMatthew G. Knepley     numFIndices += dof;
85497c927364SMatthew G. Knepley   }
85507c927364SMatthew G. Knepley   for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f];
85517c927364SMatthew G. Knepley 
85521dca8a05SBarry 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);
85531dca8a05SBarry 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);
85547c927364SMatthew G. Knepley   if (numFields) {
85554acb8e1eSToby Isaac     const PetscInt **permsF[32] = {NULL};
85564acb8e1eSToby Isaac     const PetscInt **permsC[32] = {NULL};
85574acb8e1eSToby Isaac 
85584acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
85599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
85609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
85617c927364SMatthew G. Knepley     }
85624acb8e1eSToby Isaac     for (p = 0; p < numFPoints; p++) {
85639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
85649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices));
85654acb8e1eSToby Isaac     }
85664acb8e1eSToby Isaac     for (p = 0; p < numCPoints; p++) {
85679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
85689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices));
85694acb8e1eSToby Isaac     }
85704acb8e1eSToby Isaac     for (f = 0; f < numFields; f++) {
85719566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL));
85729566063dSJacob Faibussowitsch       PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL));
85737c927364SMatthew G. Knepley     }
85747c927364SMatthew G. Knepley   } else {
85754acb8e1eSToby Isaac     const PetscInt **permsF = NULL;
85764acb8e1eSToby Isaac     const PetscInt **permsC = NULL;
85774acb8e1eSToby Isaac 
85789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
85799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL));
85804acb8e1eSToby Isaac     for (p = 0, off = 0; p < numFPoints; p++) {
85814acb8e1eSToby Isaac       const PetscInt *perm = permsF ? permsF[p] : NULL;
85824acb8e1eSToby Isaac 
85839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff));
85849566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices));
85857c927364SMatthew G. Knepley     }
85864acb8e1eSToby Isaac     for (p = 0, off = 0; p < numCPoints; p++) {
85874acb8e1eSToby Isaac       const PetscInt *perm = permsC ? permsC[p] : NULL;
85884acb8e1eSToby Isaac 
85899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff));
85909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices));
85917c927364SMatthew G. Knepley     }
85929566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL));
85939566063dSJacob Faibussowitsch     PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL));
85947c927364SMatthew G. Knepley   }
85959566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints));
85969566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints));
85973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85987c927364SMatthew G. Knepley }
85997c927364SMatthew G. Knepley 
86007cd05799SMatthew G. Knepley /*@C
86017cd05799SMatthew G. Knepley   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
86027cd05799SMatthew G. Knepley 
86037cd05799SMatthew G. Knepley   Input Parameter:
8604a1cb98faSBarry Smith . dm - The `DMPLEX` object
86057cd05799SMatthew G. Knepley 
86067cd05799SMatthew G. Knepley   Output Parameter:
86077cd05799SMatthew G. Knepley . cellHeight - The height of a cell
86087cd05799SMatthew G. Knepley 
86097cd05799SMatthew G. Knepley   Level: developer
86107cd05799SMatthew G. Knepley 
86111cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()`
86127cd05799SMatthew G. Knepley @*/
8613d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8614d71ae5a4SJacob Faibussowitsch {
8615552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8616552f7358SJed Brown 
8617552f7358SJed Brown   PetscFunctionBegin;
8618552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86194f572ea9SToby Isaac   PetscAssertPointer(cellHeight, 2);
8620552f7358SJed Brown   *cellHeight = mesh->vtkCellHeight;
86213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8622552f7358SJed Brown }
8623552f7358SJed Brown 
86247cd05799SMatthew G. Knepley /*@C
86257cd05799SMatthew G. Knepley   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
86267cd05799SMatthew G. Knepley 
86277cd05799SMatthew G. Knepley   Input Parameters:
8628a1cb98faSBarry Smith + dm         - The `DMPLEX` object
86297cd05799SMatthew G. Knepley - cellHeight - The height of a cell
86307cd05799SMatthew G. Knepley 
86317cd05799SMatthew G. Knepley   Level: developer
86327cd05799SMatthew G. Knepley 
86331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()`
86347cd05799SMatthew G. Knepley @*/
8635d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8636d71ae5a4SJacob Faibussowitsch {
8637552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8638552f7358SJed Brown 
8639552f7358SJed Brown   PetscFunctionBegin;
8640552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8641552f7358SJed Brown   mesh->vtkCellHeight = cellHeight;
86423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8643552f7358SJed Brown }
8644552f7358SJed Brown 
8645e6139122SMatthew G. Knepley /*@
86462827ebadSStefano Zampini   DMPlexGetCellTypeStratum - Get the range of cells of a given celltype
8647e6139122SMatthew G. Knepley 
86482827ebadSStefano Zampini   Input Parameters:
86492827ebadSStefano Zampini + dm - The `DMPLEX` object
86502827ebadSStefano Zampini - ct - The `DMPolytopeType` of the cell
8651e6139122SMatthew G. Knepley 
8652e6139122SMatthew G. Knepley   Output Parameters:
86532827ebadSStefano Zampini + start - The first cell of this type, or `NULL`
86542827ebadSStefano Zampini - end   - The upper bound on this celltype, or `NULL`
8655e6139122SMatthew G. Knepley 
86562a9f31c0SMatthew G. Knepley   Level: advanced
8657e6139122SMatthew G. Knepley 
86582827ebadSStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
8659e6139122SMatthew G. Knepley @*/
86602827ebadSStefano Zampini PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end)
8661d71ae5a4SJacob Faibussowitsch {
86622827ebadSStefano Zampini   DM_Plex *mesh = (DM_Plex *)dm->data;
86632827ebadSStefano Zampini   DMLabel  label;
86642827ebadSStefano Zampini   PetscInt pStart, pEnd;
8665e6139122SMatthew G. Knepley 
8666e6139122SMatthew G. Knepley   PetscFunctionBegin;
8667e6139122SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
86682827ebadSStefano Zampini   if (start) {
86694f572ea9SToby Isaac     PetscAssertPointer(start, 3);
86702827ebadSStefano Zampini     *start = 0;
86712827ebadSStefano Zampini   }
86722827ebadSStefano Zampini   if (end) {
86734f572ea9SToby Isaac     PetscAssertPointer(end, 4);
86742827ebadSStefano Zampini     *end = 0;
86752827ebadSStefano Zampini   }
86762827ebadSStefano Zampini   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
86772827ebadSStefano Zampini   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
86782827ebadSStefano Zampini   if (mesh->tr) {
86792827ebadSStefano Zampini     PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end));
86802827ebadSStefano Zampini   } else {
86812827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeLabel(dm, &label));
86822827ebadSStefano Zampini     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found");
86832827ebadSStefano Zampini     PetscCall(DMLabelGetStratumBounds(label, ct, start, end));
86842827ebadSStefano Zampini   }
86853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8686e6139122SMatthew G. Knepley }
8687e6139122SMatthew G. Knepley 
8688d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8689d71ae5a4SJacob Faibussowitsch {
8690552f7358SJed Brown   PetscSection section, globalSection;
8691552f7358SJed Brown   PetscInt    *numbers, p;
8692552f7358SJed Brown 
8693552f7358SJed Brown   PetscFunctionBegin;
8694d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE));
86959566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
86969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
869748a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1));
86989566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
86999566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection));
87009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &numbers));
8701552f7358SJed Brown   for (p = pStart; p < pEnd; ++p) {
87029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart]));
8703ef48cebcSMatthew G. Knepley     if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift;
8704ef48cebcSMatthew G. Knepley     else numbers[p - pStart] += shift;
8705552f7358SJed Brown   }
87069566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering));
8707ef48cebcSMatthew G. Knepley   if (globalSize) {
8708ef48cebcSMatthew G. Knepley     PetscLayout layout;
87099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout));
87109566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, globalSize));
87119566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
8712ef48cebcSMatthew G. Knepley   }
87139566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
87149566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&globalSection));
87153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8716552f7358SJed Brown }
8717552f7358SJed Brown 
8718d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8719d71ae5a4SJacob Faibussowitsch {
8720412e9a14SMatthew G. Knepley   PetscInt cellHeight, cStart, cEnd;
8721552f7358SJed Brown 
8722552f7358SJed Brown   PetscFunctionBegin;
87239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
87249566063dSJacob Faibussowitsch   if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
87259566063dSJacob Faibussowitsch   else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
87269566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers));
87273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8728552f7358SJed Brown }
872981ed3555SMatthew G. Knepley 
87308dab3259SMatthew G. Knepley /*@
87317cd05799SMatthew G. Knepley   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
87327cd05799SMatthew G. Knepley 
87337cd05799SMatthew G. Knepley   Input Parameter:
8734a1cb98faSBarry Smith . dm - The `DMPLEX` object
87357cd05799SMatthew G. Knepley 
87367cd05799SMatthew G. Knepley   Output Parameter:
87377cd05799SMatthew G. Knepley . globalCellNumbers - Global cell numbers for all cells on this process
87387cd05799SMatthew G. Knepley 
87397cd05799SMatthew G. Knepley   Level: developer
87407cd05799SMatthew G. Knepley 
87411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()`
87427cd05799SMatthew G. Knepley @*/
8743d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8744d71ae5a4SJacob Faibussowitsch {
874581ed3555SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
874681ed3555SMatthew G. Knepley 
874781ed3555SMatthew G. Knepley   PetscFunctionBegin;
874881ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87499566063dSJacob Faibussowitsch   if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers));
8750552f7358SJed Brown   *globalCellNumbers = mesh->globalCellNumbers;
87513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8752552f7358SJed Brown }
8753552f7358SJed Brown 
8754d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8755d71ae5a4SJacob Faibussowitsch {
8756412e9a14SMatthew G. Knepley   PetscInt vStart, vEnd;
875781ed3555SMatthew G. Knepley 
875881ed3555SMatthew G. Knepley   PetscFunctionBegin;
875981ed3555SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
87619566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers));
87623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
876381ed3555SMatthew G. Knepley }
876481ed3555SMatthew G. Knepley 
87658dab3259SMatthew G. Knepley /*@
87666aa51ba9SJacob Faibussowitsch   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
87677cd05799SMatthew G. Knepley 
87687cd05799SMatthew G. Knepley   Input Parameter:
8769a1cb98faSBarry Smith . dm - The `DMPLEX` object
87707cd05799SMatthew G. Knepley 
87717cd05799SMatthew G. Knepley   Output Parameter:
87727cd05799SMatthew G. Knepley . globalVertexNumbers - Global vertex numbers for all vertices on this process
87737cd05799SMatthew G. Knepley 
87747cd05799SMatthew G. Knepley   Level: developer
87757cd05799SMatthew G. Knepley 
87761cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
87777cd05799SMatthew G. Knepley @*/
8778d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8779d71ae5a4SJacob Faibussowitsch {
8780552f7358SJed Brown   DM_Plex *mesh = (DM_Plex *)dm->data;
8781552f7358SJed Brown 
8782552f7358SJed Brown   PetscFunctionBegin;
8783552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87849566063dSJacob Faibussowitsch   if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers));
8785552f7358SJed Brown   *globalVertexNumbers = mesh->globalVertexNumbers;
87863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8787552f7358SJed Brown }
8788552f7358SJed Brown 
87898dab3259SMatthew G. Knepley /*@
8790966484cfSJed Brown   DMPlexCreatePointNumbering - Create a global numbering for all points.
8791966484cfSJed Brown 
879220f4b53cSBarry Smith   Collective
87937cd05799SMatthew G. Knepley 
87947cd05799SMatthew G. Knepley   Input Parameter:
8795a1cb98faSBarry Smith . dm - The `DMPLEX` object
87967cd05799SMatthew G. Knepley 
87977cd05799SMatthew G. Knepley   Output Parameter:
87987cd05799SMatthew G. Knepley . globalPointNumbers - Global numbers for all points on this process
87997cd05799SMatthew G. Knepley 
8800a1cb98faSBarry Smith   Level: developer
8801966484cfSJed Brown 
8802a1cb98faSBarry Smith   Notes:
8803a1cb98faSBarry Smith   The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global
8804966484cfSJed Brown   points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points
8805966484cfSJed Brown   will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example,
8806966484cfSJed Brown   consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0.
8807966484cfSJed Brown 
8808966484cfSJed Brown   The partitioned mesh is
8809966484cfSJed Brown   ```
8810966484cfSJed Brown   (2)--0--(3)--1--(4)    (1)--0--(2)
8811966484cfSJed Brown   ```
8812966484cfSJed Brown   and its global numbering is
8813966484cfSJed Brown   ```
8814966484cfSJed Brown   (3)--0--(4)--1--(5)--2--(6)
8815966484cfSJed Brown   ```
8816966484cfSJed Brown   Then the global numbering is provided as
8817966484cfSJed Brown   ```
8818966484cfSJed Brown   [0] Number of indices in set 5
8819966484cfSJed Brown   [0] 0 0
8820966484cfSJed Brown   [0] 1 1
8821966484cfSJed Brown   [0] 2 3
8822966484cfSJed Brown   [0] 3 4
8823966484cfSJed Brown   [0] 4 -6
8824966484cfSJed Brown   [1] Number of indices in set 3
8825966484cfSJed Brown   [1] 0 2
8826966484cfSJed Brown   [1] 1 5
8827966484cfSJed Brown   [1] 2 6
8828966484cfSJed Brown   ```
8829966484cfSJed Brown 
88301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`
88317cd05799SMatthew G. Knepley @*/
8832d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8833d71ae5a4SJacob Faibussowitsch {
8834ef48cebcSMatthew G. Knepley   IS        nums[4];
8835862913ffSStefano Zampini   PetscInt  depths[4], gdepths[4], starts[4];
8836ef48cebcSMatthew G. Knepley   PetscInt  depth, d, shift = 0;
88370c15888dSMatthew G. Knepley   PetscBool empty = PETSC_FALSE;
8838ef48cebcSMatthew G. Knepley 
8839ef48cebcSMatthew G. Knepley   PetscFunctionBegin;
8840ef48cebcSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
88419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
88420c15888dSMatthew G. Knepley   // For unstratified meshes use dim instead of depth
88439566063dSJacob Faibussowitsch   if (depth < 0) PetscCall(DMGetDimension(dm, &depth));
88440c15888dSMatthew G. Knepley   // If any stratum is empty, we must mark all empty
8845862913ffSStefano Zampini   for (d = 0; d <= depth; ++d) {
8846862913ffSStefano Zampini     PetscInt end;
8847862913ffSStefano Zampini 
8848862913ffSStefano Zampini     depths[d] = depth - d;
88499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end));
88500c15888dSMatthew G. Knepley     if (!(starts[d] - end)) empty = PETSC_TRUE;
8851862913ffSStefano Zampini   }
88520c15888dSMatthew G. Knepley   if (empty)
88530c15888dSMatthew G. Knepley     for (d = 0; d <= depth; ++d) {
88540c15888dSMatthew G. Knepley       depths[d] = -1;
88550c15888dSMatthew G. Knepley       starts[d] = -1;
88560c15888dSMatthew G. Knepley     }
88570c15888dSMatthew G. Knepley   else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths));
88581c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
8859ad540459SPierre 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]);
88600c15888dSMatthew G. Knepley   // Note here that 'shift' is collective, so that the numbering is stratified by depth
8861ef48cebcSMatthew G. Knepley   for (d = 0; d <= depth; ++d) {
8862ef48cebcSMatthew G. Knepley     PetscInt pStart, pEnd, gsize;
8863ef48cebcSMatthew G. Knepley 
88649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd));
88659566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]));
8866ef48cebcSMatthew G. Knepley     shift += gsize;
8867ef48cebcSMatthew G. Knepley   }
8868d1c35871SJed Brown   PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers));
88699566063dSJacob Faibussowitsch   for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d]));
88703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8871ef48cebcSMatthew G. Knepley }
8872ef48cebcSMatthew G. Knepley 
887308a22f4bSMatthew G. Knepley /*@
887408a22f4bSMatthew G. Knepley   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
887508a22f4bSMatthew G. Knepley 
887608a22f4bSMatthew G. Knepley   Input Parameter:
8877a1cb98faSBarry Smith . dm - The `DMPLEX` object
887808a22f4bSMatthew G. Knepley 
887908a22f4bSMatthew G. Knepley   Output Parameter:
888008a22f4bSMatthew G. Knepley . ranks - The rank field
888108a22f4bSMatthew G. Knepley 
8882a1cb98faSBarry Smith   Options Database Key:
888320f4b53cSBarry Smith . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer
888408a22f4bSMatthew G. Knepley 
888508a22f4bSMatthew G. Knepley   Level: intermediate
888608a22f4bSMatthew G. Knepley 
88871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
888808a22f4bSMatthew G. Knepley @*/
8889d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8890d71ae5a4SJacob Faibussowitsch {
889108a22f4bSMatthew G. Knepley   DM             rdm;
889208a22f4bSMatthew G. Knepley   PetscFE        fe;
889308a22f4bSMatthew G. Knepley   PetscScalar   *r;
889408a22f4bSMatthew G. Knepley   PetscMPIInt    rank;
8895a55f9a55SMatthew G. Knepley   DMPolytopeType ct;
889608a22f4bSMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c;
8897a55f9a55SMatthew G. Knepley   PetscBool      simplex;
889808a22f4bSMatthew G. Knepley 
889908a22f4bSMatthew G. Knepley   PetscFunctionBeginUser;
8900f95ace6aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89014f572ea9SToby Isaac   PetscAssertPointer(ranks, 2);
89029566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
89039566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
89049566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
89059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
89069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8907a55f9a55SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
89089566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe));
89099566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "rank"));
89109566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
89119566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
89129566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
89139566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, ranks));
89149566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition"));
89159566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*ranks, &r));
891608a22f4bSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
891708a22f4bSMatthew G. Knepley     PetscScalar *lr;
891808a22f4bSMatthew G. Knepley 
89199566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr));
892071f09efeSPierre Jolivet     if (lr) *lr = rank;
892108a22f4bSMatthew G. Knepley   }
89229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*ranks, &r));
89239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
89243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
892508a22f4bSMatthew G. Knepley }
892608a22f4bSMatthew G. Knepley 
8927ca8062c8SMatthew G. Knepley /*@
892818e14f0cSMatthew G. Knepley   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
892918e14f0cSMatthew G. Knepley 
893018e14f0cSMatthew G. Knepley   Input Parameters:
893120f4b53cSBarry Smith + dm    - The `DMPLEX`
893220f4b53cSBarry Smith - label - The `DMLabel`
893318e14f0cSMatthew G. Knepley 
893418e14f0cSMatthew G. Knepley   Output Parameter:
893518e14f0cSMatthew G. Knepley . val - The label value field
893618e14f0cSMatthew G. Knepley 
893720f4b53cSBarry Smith   Options Database Key:
893820f4b53cSBarry Smith . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer
893918e14f0cSMatthew G. Knepley 
894018e14f0cSMatthew G. Knepley   Level: intermediate
894118e14f0cSMatthew G. Knepley 
89421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`
894318e14f0cSMatthew G. Knepley @*/
8944d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8945d71ae5a4SJacob Faibussowitsch {
894618e14f0cSMatthew G. Knepley   DM           rdm;
894718e14f0cSMatthew G. Knepley   PetscFE      fe;
894818e14f0cSMatthew G. Knepley   PetscScalar *v;
894918e14f0cSMatthew G. Knepley   PetscInt     dim, cStart, cEnd, c;
895018e14f0cSMatthew G. Knepley 
895118e14f0cSMatthew G. Knepley   PetscFunctionBeginUser;
895218e14f0cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
89534f572ea9SToby Isaac   PetscAssertPointer(label, 2);
89544f572ea9SToby Isaac   PetscAssertPointer(val, 3);
89559566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &rdm));
89569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(rdm, &dim));
89579566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe));
89589566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)fe, "label_value"));
89599566063dSJacob Faibussowitsch   PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe));
89609566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
89619566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(rdm));
89629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd));
89639566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(rdm, val));
89649566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*val, "label_value"));
89659566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*val, &v));
896618e14f0cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
896718e14f0cSMatthew G. Knepley     PetscScalar *lv;
896818e14f0cSMatthew G. Knepley     PetscInt     cval;
896918e14f0cSMatthew G. Knepley 
89709566063dSJacob Faibussowitsch     PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv));
89719566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(label, c, &cval));
897218e14f0cSMatthew G. Knepley     *lv = cval;
897318e14f0cSMatthew G. Knepley   }
89749566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*val, &v));
89759566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
89763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
897718e14f0cSMatthew G. Knepley }
897818e14f0cSMatthew G. Knepley 
897918e14f0cSMatthew G. Knepley /*@
8980ca8062c8SMatthew G. Knepley   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8981ca8062c8SMatthew G. Knepley 
898269916449SMatthew G. Knepley   Input Parameter:
8983a1cb98faSBarry Smith . dm - The `DMPLEX` object
8984a1cb98faSBarry Smith 
8985a1cb98faSBarry Smith   Level: developer
8986ca8062c8SMatthew G. Knepley 
898795eb5ee5SVaclav Hapla   Notes:
898895eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
898995eb5ee5SVaclav Hapla 
899020f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
8991ca8062c8SMatthew G. Knepley 
89921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
8993ca8062c8SMatthew G. Knepley @*/
8994d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSymmetry(DM dm)
8995d71ae5a4SJacob Faibussowitsch {
8996ca8062c8SMatthew G. Knepley   PetscSection    coneSection, supportSection;
8997ca8062c8SMatthew G. Knepley   const PetscInt *cone, *support;
8998ca8062c8SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
899957beb4faSStefano Zampini   PetscInt        pStart, pEnd, p, pp, csize, ssize;
900057beb4faSStefano Zampini   PetscBool       storagecheck = PETSC_TRUE;
9001ca8062c8SMatthew G. Knepley 
9002ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9003ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90049566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view"));
90059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &coneSection));
90069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSection(dm, &supportSection));
9007ca8062c8SMatthew G. Knepley   /* Check that point p is found in the support of its cone points, and vice versa */
90089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9009ca8062c8SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
90109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
90119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, p, &cone));
9012ca8062c8SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
901342e66dfaSMatthew G. Knepley       PetscBool dup = PETSC_FALSE;
901442e66dfaSMatthew G. Knepley       PetscInt  d;
901542e66dfaSMatthew G. Knepley       for (d = c - 1; d >= 0; --d) {
90169371c9d4SSatish Balay         if (cone[c] == cone[d]) {
90179371c9d4SSatish Balay           dup = PETSC_TRUE;
90189371c9d4SSatish Balay           break;
90199371c9d4SSatish Balay         }
902042e66dfaSMatthew G. Knepley       }
90219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize));
90229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[c], &support));
9023ca8062c8SMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
9024ca8062c8SMatthew G. Knepley         if (support[s] == p) break;
9025ca8062c8SMatthew G. Knepley       }
902642e66dfaSMatthew G. Knepley       if ((s >= supportSize) || (dup && (support[s + 1] != p))) {
902763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p));
902848a46eb9SPierre Jolivet         for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s]));
90299566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
903063a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c]));
903148a46eb9SPierre Jolivet         for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s]));
90329566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
903363a3b9bcSJacob 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]);
9034f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]);
9035ca8062c8SMatthew G. Knepley       }
903642e66dfaSMatthew G. Knepley     }
90379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL));
90389371c9d4SSatish Balay     if (p != pp) {
90399371c9d4SSatish Balay       storagecheck = PETSC_FALSE;
90409371c9d4SSatish Balay       continue;
90419371c9d4SSatish Balay     }
90429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
90439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &support));
9044ca8062c8SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
90459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
90469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, support[s], &cone));
9047ca8062c8SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
90489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL));
90499371c9d4SSatish Balay         if (cone[c] != pp) {
90509371c9d4SSatish Balay           c = 0;
90519371c9d4SSatish Balay           break;
90529371c9d4SSatish Balay         }
9053ca8062c8SMatthew G. Knepley         if (cone[c] == p) break;
9054ca8062c8SMatthew G. Knepley       }
9055ca8062c8SMatthew G. Knepley       if (c >= coneSize) {
905663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p));
905748a46eb9SPierre Jolivet         for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c]));
90589566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
905963a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s]));
906048a46eb9SPierre Jolivet         for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c]));
90619566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
906263a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]);
9063ca8062c8SMatthew G. Knepley       }
9064ca8062c8SMatthew G. Knepley     }
9065ca8062c8SMatthew G. Knepley   }
906657beb4faSStefano Zampini   if (storagecheck) {
90679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coneSection, &csize));
90689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(supportSection, &ssize));
906963a3b9bcSJacob Faibussowitsch     PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize);
907057beb4faSStefano Zampini   }
90713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9072ca8062c8SMatthew G. Knepley }
9073ca8062c8SMatthew G. Knepley 
9074412e9a14SMatthew G. Knepley /*
9075412e9a14SMatthew 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.
9076412e9a14SMatthew G. Knepley */
9077d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
9078d71ae5a4SJacob Faibussowitsch {
9079412e9a14SMatthew G. Knepley   DMPolytopeType  cct;
9080412e9a14SMatthew G. Knepley   PetscInt        ptpoints[4];
9081412e9a14SMatthew G. Knepley   const PetscInt *cone, *ccone, *ptcone;
9082412e9a14SMatthew G. Knepley   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
9083412e9a14SMatthew G. Knepley 
9084412e9a14SMatthew G. Knepley   PetscFunctionBegin;
9085412e9a14SMatthew G. Knepley   *unsplit = 0;
9086412e9a14SMatthew G. Knepley   switch (ct) {
9087d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_POINT_PRISM_TENSOR:
9088d71ae5a4SJacob Faibussowitsch     ptpoints[npt++] = c;
9089d71ae5a4SJacob Faibussowitsch     break;
9090412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
90919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
90929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9093412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
90949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[cp], &cct));
9095412e9a14SMatthew G. Knepley       if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
9096412e9a14SMatthew G. Knepley     }
9097412e9a14SMatthew G. Knepley     break;
9098412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
9099412e9a14SMatthew G. Knepley   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
91009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
91019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
9102412e9a14SMatthew G. Knepley     for (cp = 0; cp < coneSize; ++cp) {
91039566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cone[cp], &ccone));
91049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize));
9105412e9a14SMatthew G. Knepley       for (ccp = 0; ccp < cconeSize; ++ccp) {
91069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct));
9107412e9a14SMatthew G. Knepley         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
9108412e9a14SMatthew G. Knepley           PetscInt p;
91099371c9d4SSatish Balay           for (p = 0; p < npt; ++p)
91109371c9d4SSatish Balay             if (ptpoints[p] == ccone[ccp]) break;
9111412e9a14SMatthew G. Knepley           if (p == npt) ptpoints[npt++] = ccone[ccp];
9112412e9a14SMatthew G. Knepley         }
9113412e9a14SMatthew G. Knepley       }
9114412e9a14SMatthew G. Knepley     }
9115412e9a14SMatthew G. Knepley     break;
9116d71ae5a4SJacob Faibussowitsch   default:
9117d71ae5a4SJacob Faibussowitsch     break;
9118412e9a14SMatthew G. Knepley   }
9119412e9a14SMatthew G. Knepley   for (pt = 0; pt < npt; ++pt) {
91209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone));
9121412e9a14SMatthew G. Knepley     if (ptcone[0] == ptcone[1]) ++(*unsplit);
9122412e9a14SMatthew G. Knepley   }
91233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9124412e9a14SMatthew G. Knepley }
9125412e9a14SMatthew G. Knepley 
9126ca8062c8SMatthew G. Knepley /*@
9127ca8062c8SMatthew G. Knepley   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
9128ca8062c8SMatthew G. Knepley 
9129ca8062c8SMatthew G. Knepley   Input Parameters:
9130a1cb98faSBarry Smith + dm         - The `DMPLEX` object
913158723a97SMatthew G. Knepley - cellHeight - Normally 0
9132ca8062c8SMatthew G. Knepley 
9133a1cb98faSBarry Smith   Level: developer
9134a1cb98faSBarry Smith 
913595eb5ee5SVaclav Hapla   Notes:
913695eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
913725c50c26SVaclav Hapla   Currently applicable only to homogeneous simplex or tensor meshes.
9138ca8062c8SMatthew G. Knepley 
913920f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
914095eb5ee5SVaclav Hapla 
91411cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9142ca8062c8SMatthew G. Knepley @*/
9143d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
9144d71ae5a4SJacob Faibussowitsch {
9145412e9a14SMatthew G. Knepley   DMPlexInterpolatedFlag interp;
9146412e9a14SMatthew G. Knepley   DMPolytopeType         ct;
9147412e9a14SMatthew G. Knepley   PetscInt               vStart, vEnd, cStart, cEnd, c;
9148ca8062c8SMatthew G. Knepley 
9149ca8062c8SMatthew G. Knepley   PetscFunctionBegin;
9150ca8062c8SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91519566063dSJacob Faibussowitsch   PetscCall(DMPlexIsInterpolated(dm, &interp));
91529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
91539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9154412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9155412e9a14SMatthew G. Knepley     PetscInt *closure = NULL;
9156412e9a14SMatthew G. Knepley     PetscInt  coneSize, closureSize, cl, Nv = 0;
915758723a97SMatthew G. Knepley 
91589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
915963a3b9bcSJacob Faibussowitsch     PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c);
9160412e9a14SMatthew G. Knepley     if (ct == DM_POLYTOPE_UNKNOWN) continue;
9161412e9a14SMatthew G. Knepley     if (interp == DMPLEX_INTERPOLATED_FULL) {
91629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
916363a3b9bcSJacob 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));
9164412e9a14SMatthew G. Knepley     }
91659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
916658723a97SMatthew G. Knepley     for (cl = 0; cl < closureSize * 2; cl += 2) {
916758723a97SMatthew G. Knepley       const PetscInt p = closure[cl];
9168412e9a14SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++Nv;
916958723a97SMatthew G. Knepley     }
91709566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
9171412e9a14SMatthew G. Knepley     /* Special Case: Tensor faces with identified vertices */
9172412e9a14SMatthew G. Knepley     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
9173412e9a14SMatthew G. Knepley       PetscInt unsplit;
917442363296SMatthew G. Knepley 
91759566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9176412e9a14SMatthew G. Knepley       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
917742363296SMatthew G. Knepley     }
917863a3b9bcSJacob 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));
917942363296SMatthew G. Knepley   }
91803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9181ca8062c8SMatthew G. Knepley }
91829bf0dad6SMatthew G. Knepley 
91839bf0dad6SMatthew G. Knepley /*@
91849bf0dad6SMatthew 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
91859bf0dad6SMatthew G. Knepley 
918620f4b53cSBarry Smith   Collective
9187899ea2b8SJacob Faibussowitsch 
91889bf0dad6SMatthew G. Knepley   Input Parameters:
9189a1cb98faSBarry Smith + dm         - The `DMPLEX` object
91909bf0dad6SMatthew G. Knepley - cellHeight - Normally 0
91919bf0dad6SMatthew G. Knepley 
9192a1cb98faSBarry Smith   Level: developer
9193a1cb98faSBarry Smith 
919445da879fSVaclav Hapla   Notes:
919545da879fSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
919645da879fSVaclav Hapla   This routine is only relevant for meshes that are fully interpolated across all ranks.
919745da879fSVaclav Hapla   It will error out if a partially interpolated mesh is given on some rank.
919845da879fSVaclav Hapla   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
91999bf0dad6SMatthew G. Knepley 
9200a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
920195eb5ee5SVaclav Hapla 
92021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()`
92039bf0dad6SMatthew G. Knepley @*/
9204d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
9205d71ae5a4SJacob Faibussowitsch {
9206ab91121cSMatthew G. Knepley   PetscInt               dim, depth, vStart, vEnd, cStart, cEnd, c, h;
9207899ea2b8SJacob Faibussowitsch   DMPlexInterpolatedFlag interpEnum;
92089bf0dad6SMatthew G. Knepley 
92099bf0dad6SMatthew G. Knepley   PetscFunctionBegin;
92109bf0dad6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
92118f6815adSVaclav Hapla   PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum));
92123ba16761SJacob Faibussowitsch   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS);
92138f6815adSVaclav Hapla   if (interpEnum != DMPLEX_INTERPOLATED_FULL) {
92143ba16761SJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"));
92153ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
9216899ea2b8SJacob Faibussowitsch   }
9217899ea2b8SJacob Faibussowitsch 
92189566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
92199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
92209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9221ab91121cSMatthew G. Knepley   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
92229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
92233554e41dSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
9224412e9a14SMatthew G. Knepley       const PetscInt       *cone, *ornt, *faceSizes, *faces;
9225412e9a14SMatthew G. Knepley       const DMPolytopeType *faceTypes;
9226ba2698f1SMatthew G. Knepley       DMPolytopeType        ct;
9227412e9a14SMatthew G. Knepley       PetscInt              numFaces, coneSize, f;
9228412e9a14SMatthew G. Knepley       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
92299bf0dad6SMatthew G. Knepley 
92309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, c, &ct));
92319566063dSJacob Faibussowitsch       PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9232412e9a14SMatthew G. Knepley       if (unsplit) continue;
92339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
92349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, c, &cone));
92359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, c, &ornt));
92369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
92379bf0dad6SMatthew G. Knepley       for (cl = 0; cl < closureSize * 2; cl += 2) {
92389bf0dad6SMatthew G. Knepley         const PetscInt p = closure[cl];
92399bf0dad6SMatthew G. Knepley         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
92409bf0dad6SMatthew G. Knepley       }
92419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
924263a3b9bcSJacob 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);
92439bf0dad6SMatthew G. Knepley       for (f = 0; f < numFaces; ++f) {
9244d4961f80SStefano Zampini         DMPolytopeType fct;
92459bf0dad6SMatthew G. Knepley         PetscInt      *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
92469bf0dad6SMatthew G. Knepley 
92479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, cone[f], &fct));
92489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure));
92499bf0dad6SMatthew G. Knepley         for (cl = 0; cl < fclosureSize * 2; cl += 2) {
92509bf0dad6SMatthew G. Knepley           const PetscInt p = fclosure[cl];
92519bf0dad6SMatthew G. Knepley           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
92529bf0dad6SMatthew G. Knepley         }
925363a3b9bcSJacob 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]);
92549bf0dad6SMatthew G. Knepley         for (v = 0; v < fnumCorners; ++v) {
9255b5a892a1SMatthew G. Knepley           if (fclosure[v] != faces[fOff + v]) {
9256b5a892a1SMatthew G. Knepley             PetscInt v1;
9257b5a892a1SMatthew G. Knepley 
92589566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:"));
925963a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1]));
92609566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:"));
926163a3b9bcSJacob Faibussowitsch             for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1]));
92629566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
926363a3b9bcSJacob 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]);
9264b5a892a1SMatthew G. Knepley           }
92659bf0dad6SMatthew G. Knepley         }
92669566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure));
9267412e9a14SMatthew G. Knepley         fOff += faceSizes[f];
92689bf0dad6SMatthew G. Knepley       }
92699566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces));
92709566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
92719bf0dad6SMatthew G. Knepley     }
92723554e41dSMatthew G. Knepley   }
92733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9274552f7358SJed Brown }
92753913d7c8SMatthew G. Knepley 
9276bb6a34a8SMatthew G. Knepley /*@
9277bb6a34a8SMatthew G. Knepley   DMPlexCheckGeometry - Check the geometry of mesh cells
9278bb6a34a8SMatthew G. Knepley 
9279bb6a34a8SMatthew G. Knepley   Input Parameter:
9280a1cb98faSBarry Smith . dm - The `DMPLEX` object
9281a1cb98faSBarry Smith 
9282a1cb98faSBarry Smith   Level: developer
9283bb6a34a8SMatthew G. Knepley 
928495eb5ee5SVaclav Hapla   Notes:
928595eb5ee5SVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
928695eb5ee5SVaclav Hapla 
928720f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9288bb6a34a8SMatthew G. Knepley 
92891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
9290bb6a34a8SMatthew G. Knepley @*/
9291d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckGeometry(DM dm)
9292d71ae5a4SJacob Faibussowitsch {
9293a2a9e04cSMatthew G. Knepley   Vec       coordinates;
9294bb6a34a8SMatthew G. Knepley   PetscReal detJ, J[9], refVol = 1.0;
9295bb6a34a8SMatthew G. Knepley   PetscReal vol;
929651a74b61SMatthew G. Knepley   PetscInt  dim, depth, dE, d, cStart, cEnd, c;
9297bb6a34a8SMatthew G. Knepley 
9298bb6a34a8SMatthew G. Knepley   PetscFunctionBegin;
92999566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
93009566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
93013ba16761SJacob Faibussowitsch   if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS);
93029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
9303bb6a34a8SMatthew G. Knepley   for (d = 0; d < dim; ++d) refVol *= 2.0;
93049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9305a2a9e04cSMatthew G. Knepley   /* Make sure local coordinates are created, because that step is collective */
93069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
93073ba16761SJacob Faibussowitsch   if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS);
9308412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
9309412e9a14SMatthew G. Knepley     DMPolytopeType ct;
9310412e9a14SMatthew G. Knepley     PetscInt       unsplit;
9311412e9a14SMatthew G. Knepley     PetscBool      ignoreZeroVol = PETSC_FALSE;
9312412e9a14SMatthew G. Knepley 
93139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, c, &ct));
9314412e9a14SMatthew G. Knepley     switch (ct) {
9315412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
9316412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9317d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9318d71ae5a4SJacob Faibussowitsch       ignoreZeroVol = PETSC_TRUE;
9319d71ae5a4SJacob Faibussowitsch       break;
9320d71ae5a4SJacob Faibussowitsch     default:
9321d71ae5a4SJacob Faibussowitsch       break;
9322412e9a14SMatthew G. Knepley     }
9323412e9a14SMatthew G. Knepley     switch (ct) {
9324412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
9325412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
9326412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
9327d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_PYRAMID:
9328d71ae5a4SJacob Faibussowitsch       continue;
9329d71ae5a4SJacob Faibussowitsch     default:
9330d71ae5a4SJacob Faibussowitsch       break;
9331412e9a14SMatthew G. Knepley     }
93329566063dSJacob Faibussowitsch     PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit));
9333412e9a14SMatthew G. Knepley     if (unsplit) continue;
93349566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ));
93351dca8a05SBarry 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);
933663a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol)));
93376858538eSMatthew G. Knepley     /* This should work with periodicity since DG coordinates should be used */
93386858538eSMatthew G. Knepley     if (depth > 1) {
93399566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
93401dca8a05SBarry 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);
934163a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol));
9342bb6a34a8SMatthew G. Knepley     }
9343bb6a34a8SMatthew G. Knepley   }
93443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9345bb6a34a8SMatthew G. Knepley }
9346bb6a34a8SMatthew G. Knepley 
934703da9461SVaclav Hapla /*@
934820f4b53cSBarry Smith   DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex.
93497726db96SVaclav Hapla 
935020f4b53cSBarry Smith   Collective
935103da9461SVaclav Hapla 
935203da9461SVaclav Hapla   Input Parameters:
9353a1cb98faSBarry Smith + dm              - The `DMPLEX` object
935420f4b53cSBarry Smith . pointSF         - The `PetscSF`, or `NULL` for `PointSF` attached to `DM`
9355a1cb98faSBarry Smith - allowExtraRoots - Flag to allow extra points not present in the `DM`
9356a1cb98faSBarry Smith 
9357a1cb98faSBarry Smith   Level: developer
935803da9461SVaclav Hapla 
9359e83a0d2dSVaclav Hapla   Notes:
9360e83a0d2dSVaclav Hapla   This is mainly intended for debugging/testing purposes.
936103da9461SVaclav Hapla 
9362a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
936395eb5ee5SVaclav Hapla 
9364baca6076SPierre Jolivet   Extra roots can come from periodic cuts, where additional points appear on the boundary
9365d7d32a9aSMatthew G. Knepley 
93661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()`
936703da9461SVaclav Hapla @*/
9368d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots)
9369d71ae5a4SJacob Faibussowitsch {
93707726db96SVaclav Hapla   PetscInt           l, nleaves, nroots, overlap;
93717726db96SVaclav Hapla   const PetscInt    *locals;
93727726db96SVaclav Hapla   const PetscSFNode *remotes;
9373f0cfc026SVaclav Hapla   PetscBool          distributed;
93747726db96SVaclav Hapla   MPI_Comm           comm;
93757726db96SVaclav Hapla   PetscMPIInt        rank;
937603da9461SVaclav Hapla 
937703da9461SVaclav Hapla   PetscFunctionBegin;
937803da9461SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
93797726db96SVaclav Hapla   if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
93807726db96SVaclav Hapla   else pointSF = dm->sf;
93817726db96SVaclav Hapla   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
93827726db96SVaclav Hapla   PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached");
93837726db96SVaclav Hapla   PetscCallMPI(MPI_Comm_rank(comm, &rank));
93847726db96SVaclav Hapla   {
93857726db96SVaclav Hapla     PetscMPIInt mpiFlag;
93867726db96SVaclav Hapla 
93877726db96SVaclav Hapla     PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag));
93887726db96SVaclav 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);
93897726db96SVaclav Hapla   }
93907726db96SVaclav Hapla   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes));
93919566063dSJacob Faibussowitsch   PetscCall(DMPlexIsDistributed(dm, &distributed));
93927726db96SVaclav Hapla   if (!distributed) {
93937726db96SVaclav 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);
93943ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
93958918e3e2SVaclav Hapla   }
93967726db96SVaclav 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);
93977726db96SVaclav Hapla   PetscCall(DMPlexGetOverlap(dm, &overlap));
939803da9461SVaclav Hapla 
93997726db96SVaclav Hapla   /* Check SF graph is compatible with DMPlex chart */
94007726db96SVaclav Hapla   {
94017726db96SVaclav Hapla     PetscInt pStart, pEnd, maxLeaf;
94027726db96SVaclav Hapla 
94037726db96SVaclav Hapla     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
94047726db96SVaclav Hapla     PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf));
9405d7d32a9aSMatthew G. Knepley     PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots);
94067726db96SVaclav Hapla     PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd);
94077726db96SVaclav Hapla   }
94087726db96SVaclav Hapla 
94097726db96SVaclav Hapla   /* Check Point SF has no local points referenced */
94107726db96SVaclav Hapla   for (l = 0; l < nleaves; l++) {
94117726db96SVaclav 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);
94127726db96SVaclav Hapla   }
94137726db96SVaclav Hapla 
94147726db96SVaclav Hapla   /* Check there are no cells in interface */
94157726db96SVaclav Hapla   if (!overlap) {
94167726db96SVaclav Hapla     PetscInt cellHeight, cStart, cEnd;
94177726db96SVaclav Hapla 
94189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
94199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
9420f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
94217726db96SVaclav Hapla       const PetscInt point = locals ? locals[l] : l;
9422f5869d18SMatthew G. Knepley 
94237726db96SVaclav Hapla       PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point);
94247726db96SVaclav Hapla     }
942503da9461SVaclav Hapla   }
9426ece87651SVaclav Hapla 
94277726db96SVaclav Hapla   /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
94287726db96SVaclav Hapla   {
94297726db96SVaclav Hapla     const PetscInt *rootdegree;
94307726db96SVaclav Hapla 
94317726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree));
94327726db96SVaclav Hapla     PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree));
9433f5869d18SMatthew G. Knepley     for (l = 0; l < nleaves; ++l) {
94347726db96SVaclav Hapla       const PetscInt  point = locals ? locals[l] : l;
9435f5869d18SMatthew G. Knepley       const PetscInt *cone;
9436f5869d18SMatthew G. Knepley       PetscInt        coneSize, c, idx;
9437f5869d18SMatthew G. Knepley 
94389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
94399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, point, &cone));
9440f5869d18SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
9441f5869d18SMatthew G. Knepley         if (!rootdegree[cone[c]]) {
94427726db96SVaclav Hapla           if (locals) {
94439566063dSJacob Faibussowitsch             PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx));
94447726db96SVaclav Hapla           } else {
94457726db96SVaclav Hapla             idx = (cone[c] < nleaves) ? cone[c] : -1;
94467726db96SVaclav Hapla           }
944763a3b9bcSJacob 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]);
9448f5869d18SMatthew G. Knepley         }
9449f5869d18SMatthew G. Knepley       }
9450ece87651SVaclav Hapla     }
94517726db96SVaclav Hapla   }
94523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
945303da9461SVaclav Hapla }
945403da9461SVaclav Hapla 
94557f9d8d6cSVaclav Hapla /*@
945620f4b53cSBarry Smith   DMPlexCheck - Perform various checks of `DMPLEX` sanity
94577f9d8d6cSVaclav Hapla 
94587f9d8d6cSVaclav Hapla   Input Parameter:
9459a1cb98faSBarry Smith . dm - The `DMPLEX` object
9460a1cb98faSBarry Smith 
9461a1cb98faSBarry Smith   Level: developer
94627f9d8d6cSVaclav Hapla 
94637f9d8d6cSVaclav Hapla   Notes:
94647f9d8d6cSVaclav Hapla   This is a useful diagnostic when creating meshes programmatically.
94657f9d8d6cSVaclav Hapla 
946620f4b53cSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
94677f9d8d6cSVaclav Hapla 
946820f4b53cSBarry Smith   Currently does not include `DMPlexCheckCellShape()`.
94697f9d8d6cSVaclav Hapla 
94701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()`
94717f9d8d6cSVaclav Hapla @*/
9472d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheck(DM dm)
9473d71ae5a4SJacob Faibussowitsch {
94747f9d8d6cSVaclav Hapla   PetscInt cellHeight;
94757f9d8d6cSVaclav Hapla 
9476b5a892a1SMatthew G. Knepley   PetscFunctionBegin;
94777f9d8d6cSVaclav Hapla   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
94789566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSymmetry(dm));
94799566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckSkeleton(dm, cellHeight));
94809566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckFaces(dm, cellHeight));
94819566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckGeometry(dm));
9482d7d32a9aSMatthew G. Knepley   PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
94839566063dSJacob Faibussowitsch   PetscCall(DMPlexCheckInterfaceCones(dm));
94843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9485b5a892a1SMatthew G. Knepley }
9486b5a892a1SMatthew G. Knepley 
94879371c9d4SSatish Balay typedef struct cell_stats {
9488068a5610SStefano Zampini   PetscReal min, max, sum, squaresum;
9489068a5610SStefano Zampini   PetscInt  count;
9490068a5610SStefano Zampini } cell_stats_t;
9491068a5610SStefano Zampini 
9492d71ae5a4SJacob Faibussowitsch static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype)
9493d71ae5a4SJacob Faibussowitsch {
9494068a5610SStefano Zampini   PetscInt i, N = *len;
9495068a5610SStefano Zampini 
9496068a5610SStefano Zampini   for (i = 0; i < N; i++) {
9497068a5610SStefano Zampini     cell_stats_t *A = (cell_stats_t *)a;
9498068a5610SStefano Zampini     cell_stats_t *B = (cell_stats_t *)b;
9499068a5610SStefano Zampini 
9500068a5610SStefano Zampini     B->min = PetscMin(A->min, B->min);
9501068a5610SStefano Zampini     B->max = PetscMax(A->max, B->max);
9502068a5610SStefano Zampini     B->sum += A->sum;
9503068a5610SStefano Zampini     B->squaresum += A->squaresum;
9504068a5610SStefano Zampini     B->count += A->count;
9505068a5610SStefano Zampini   }
9506068a5610SStefano Zampini }
9507068a5610SStefano Zampini 
9508068a5610SStefano Zampini /*@
950943fa8764SMatthew G. Knepley   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
9510068a5610SStefano Zampini 
951120f4b53cSBarry Smith   Collective
95128261a58bSMatthew G. Knepley 
9513068a5610SStefano Zampini   Input Parameters:
9514a1cb98faSBarry Smith + dm        - The `DMPLEX` object
951520f4b53cSBarry Smith . output    - If true, statistics will be displayed on `stdout`
9516a1cb98faSBarry Smith - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output
9517a1cb98faSBarry Smith 
9518a1cb98faSBarry Smith   Level: developer
9519068a5610SStefano Zampini 
952095eb5ee5SVaclav Hapla   Notes:
952195eb5ee5SVaclav Hapla   This is mainly intended for debugging/testing purposes.
952295eb5ee5SVaclav Hapla 
9523a1cb98faSBarry Smith   For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`.
9524068a5610SStefano Zampini 
95251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()`
9526068a5610SStefano Zampini @*/
9527d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
9528d71ae5a4SJacob Faibussowitsch {
9529068a5610SStefano Zampini   DM           dmCoarse;
953043fa8764SMatthew G. Knepley   cell_stats_t stats, globalStats;
953143fa8764SMatthew G. Knepley   MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
953243fa8764SMatthew G. Knepley   PetscReal   *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
953343fa8764SMatthew G. Knepley   PetscReal    limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
9534412e9a14SMatthew G. Knepley   PetscInt     cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
953543fa8764SMatthew G. Knepley   PetscMPIInt  rank, size;
9536068a5610SStefano Zampini 
9537068a5610SStefano Zampini   PetscFunctionBegin;
9538068a5610SStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9539068a5610SStefano Zampini   stats.min = PETSC_MAX_REAL;
9540068a5610SStefano Zampini   stats.max = PETSC_MIN_REAL;
9541068a5610SStefano Zampini   stats.sum = stats.squaresum = 0.;
9542068a5610SStefano Zampini   stats.count                 = 0;
9543068a5610SStefano Zampini 
95449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
95459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
95469566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
95479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ));
95489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
95499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
9550412e9a14SMatthew G. Knepley   for (c = cStart; c < cEnd; c++) {
9551068a5610SStefano Zampini     PetscInt  i;
9552068a5610SStefano Zampini     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
9553068a5610SStefano Zampini 
95549566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ));
955563a3b9bcSJacob Faibussowitsch     PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c);
955643fa8764SMatthew G. Knepley     for (i = 0; i < PetscSqr(cdim); ++i) {
9557068a5610SStefano Zampini       frobJ += J[i] * J[i];
9558068a5610SStefano Zampini       frobInvJ += invJ[i] * invJ[i];
9559068a5610SStefano Zampini     }
9560068a5610SStefano Zampini     cond2 = frobJ * frobInvJ;
9561068a5610SStefano Zampini     cond  = PetscSqrtReal(cond2);
9562068a5610SStefano Zampini 
9563068a5610SStefano Zampini     stats.min = PetscMin(stats.min, cond);
9564068a5610SStefano Zampini     stats.max = PetscMax(stats.max, cond);
9565068a5610SStefano Zampini     stats.sum += cond;
9566068a5610SStefano Zampini     stats.squaresum += cond2;
9567068a5610SStefano Zampini     stats.count++;
95688261a58bSMatthew G. Knepley     if (output && cond > limit) {
956943fa8764SMatthew G. Knepley       PetscSection coordSection;
957043fa8764SMatthew G. Knepley       Vec          coordsLocal;
957143fa8764SMatthew G. Knepley       PetscScalar *coords = NULL;
957243fa8764SMatthew G. Knepley       PetscInt     Nv, d, clSize, cl, *closure = NULL;
957343fa8764SMatthew G. Knepley 
95749566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
95759566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &coordSection));
95769566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
957763a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond));
957843fa8764SMatthew G. Knepley       for (i = 0; i < Nv / cdim; ++i) {
957963a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ": (", i));
958043fa8764SMatthew G. Knepley         for (d = 0; d < cdim; ++d) {
95819566063dSJacob Faibussowitsch           if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", "));
95829566063dSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d])));
958343fa8764SMatthew G. Knepley         }
95849566063dSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, ")\n"));
958543fa8764SMatthew G. Knepley       }
95869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
958743fa8764SMatthew G. Knepley       for (cl = 0; cl < clSize * 2; cl += 2) {
958843fa8764SMatthew G. Knepley         const PetscInt edge = closure[cl];
958943fa8764SMatthew G. Knepley 
959043fa8764SMatthew G. Knepley         if ((edge >= eStart) && (edge < eEnd)) {
959143fa8764SMatthew G. Knepley           PetscReal len;
959243fa8764SMatthew G. Knepley 
95939566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL));
959463a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT ": length %g\n", edge, (double)len));
959543fa8764SMatthew G. Knepley         }
959643fa8764SMatthew G. Knepley       }
95979566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
95989566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords));
959943fa8764SMatthew G. Knepley     }
9600068a5610SStefano Zampini   }
96019566063dSJacob Faibussowitsch   if (output) PetscCall(PetscSynchronizedFlush(comm, NULL));
9602068a5610SStefano Zampini 
9603068a5610SStefano Zampini   if (size > 1) {
9604068a5610SStefano Zampini     PetscMPIInt  blockLengths[2] = {4, 1};
9605068a5610SStefano Zampini     MPI_Aint     blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)};
9606068a5610SStefano Zampini     MPI_Datatype blockTypes[2]   = {MPIU_REAL, MPIU_INT}, statType;
9607068a5610SStefano Zampini     MPI_Op       statReduce;
9608068a5610SStefano Zampini 
96099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType));
96109566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&statType));
96119566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce));
96129566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm));
96139566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&statReduce));
96149566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&statType));
9615068a5610SStefano Zampini   } else {
96169566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&globalStats, &stats, 1));
9617068a5610SStefano Zampini   }
9618dd400576SPatrick Sanan   if (rank == 0) {
9619068a5610SStefano Zampini     count = globalStats.count;
9620068a5610SStefano Zampini     min   = globalStats.min;
9621068a5610SStefano Zampini     max   = globalStats.max;
9622068a5610SStefano Zampini     mean  = globalStats.sum / globalStats.count;
9623068a5610SStefano Zampini     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0;
9624068a5610SStefano Zampini   }
9625068a5610SStefano Zampini 
962648a46eb9SPierre 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));
96279566063dSJacob Faibussowitsch   PetscCall(PetscFree2(J, invJ));
9628068a5610SStefano Zampini 
96299566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dm, &dmCoarse));
9630068a5610SStefano Zampini   if (dmCoarse) {
9631068a5610SStefano Zampini     PetscBool isplex;
9632068a5610SStefano Zampini 
96339566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex));
96341baa6e33SBarry Smith     if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit));
9635068a5610SStefano Zampini   }
96363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9637068a5610SStefano Zampini }
9638068a5610SStefano Zampini 
9639f108dbd7SJacob Faibussowitsch /*@
9640f108dbd7SJacob Faibussowitsch   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
9641f108dbd7SJacob Faibussowitsch   orthogonal quality below given tolerance.
9642f108dbd7SJacob Faibussowitsch 
964320f4b53cSBarry Smith   Collective
9644f108dbd7SJacob Faibussowitsch 
9645f108dbd7SJacob Faibussowitsch   Input Parameters:
9646a1cb98faSBarry Smith + dm   - The `DMPLEX` object
9647a1cb98faSBarry Smith . fv   - Optional `PetscFV` object for pre-computed cell/face centroid information
9648f108dbd7SJacob Faibussowitsch - atol - [0, 1] Absolute tolerance for tagging cells.
9649f108dbd7SJacob Faibussowitsch 
9650f108dbd7SJacob Faibussowitsch   Output Parameters:
965120f4b53cSBarry Smith + OrthQual      - `Vec` containing orthogonal quality per cell
9652a1cb98faSBarry Smith - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE`
9653f108dbd7SJacob Faibussowitsch 
9654f108dbd7SJacob Faibussowitsch   Options Database Keys:
9655a1cb98faSBarry Smith + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported.
9656f108dbd7SJacob Faibussowitsch - -dm_plex_orthogonal_quality_vec_view   - view OrthQual vector.
9657f108dbd7SJacob Faibussowitsch 
9658a1cb98faSBarry Smith   Level: intermediate
9659a1cb98faSBarry Smith 
9660f108dbd7SJacob Faibussowitsch   Notes:
9661a4e35b19SJacob Faibussowitsch   Orthogonal quality is given by the following formula\:
9662f108dbd7SJacob Faibussowitsch 
9663a1cb98faSBarry Smith   $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$
9664f108dbd7SJacob Faibussowitsch 
9665f108dbd7SJacob 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
9666f108dbd7SJacob Faibussowitsch   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
9667f108dbd7SJacob Faibussowitsch   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
9668f108dbd7SJacob Faibussowitsch   calculating the cosine of the angle between these vectors.
9669f108dbd7SJacob Faibussowitsch 
9670f108dbd7SJacob Faibussowitsch   Orthogonal quality ranges from 1 (best) to 0 (worst).
9671f108dbd7SJacob Faibussowitsch 
9672a1cb98faSBarry Smith   This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for
9673f108dbd7SJacob Faibussowitsch   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
9674f108dbd7SJacob Faibussowitsch 
9675f108dbd7SJacob Faibussowitsch   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
9676f108dbd7SJacob Faibussowitsch 
96771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec`
9678f108dbd7SJacob Faibussowitsch @*/
9679d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
9680d71ae5a4SJacob Faibussowitsch {
96816ed19f2fSJacob Faibussowitsch   PetscInt               nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
96826ed19f2fSJacob Faibussowitsch   PetscInt              *idx;
96836ed19f2fSJacob Faibussowitsch   PetscScalar           *oqVals;
9684f108dbd7SJacob Faibussowitsch   const PetscScalar     *cellGeomArr, *faceGeomArr;
96856ed19f2fSJacob Faibussowitsch   PetscReal             *ci, *fi, *Ai;
9686f108dbd7SJacob Faibussowitsch   MPI_Comm               comm;
9687f108dbd7SJacob Faibussowitsch   Vec                    cellgeom, facegeom;
9688f108dbd7SJacob Faibussowitsch   DM                     dmFace, dmCell;
9689f108dbd7SJacob Faibussowitsch   IS                     glob;
9690f108dbd7SJacob Faibussowitsch   ISLocalToGlobalMapping ltog;
9691f108dbd7SJacob Faibussowitsch   PetscViewer            vwr;
9692f108dbd7SJacob Faibussowitsch 
9693f108dbd7SJacob Faibussowitsch   PetscFunctionBegin;
9694f108dbd7SJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9695ad540459SPierre Jolivet   if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
96964f572ea9SToby Isaac   PetscAssertPointer(OrthQual, 4);
96976bdcaf15SBarry Smith   PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol);
96989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
96999566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &nc));
970063a3b9bcSJacob Faibussowitsch   PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc);
97016ed19f2fSJacob Faibussowitsch   {
97026ed19f2fSJacob Faibussowitsch     DMPlexInterpolatedFlag interpFlag;
97036ed19f2fSJacob Faibussowitsch 
97049566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpFlag));
9705f108dbd7SJacob Faibussowitsch     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
9706f108dbd7SJacob Faibussowitsch       PetscMPIInt rank;
9707f108dbd7SJacob Faibussowitsch 
97089566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(comm, &rank));
970998921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
9710f108dbd7SJacob Faibussowitsch     }
97116ed19f2fSJacob Faibussowitsch   }
9712f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
97134f572ea9SToby Isaac     PetscAssertPointer(OrthQualLabel, 5);
97149566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "Orthogonal_Quality"));
97159566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel));
97169371c9d4SSatish Balay   } else {
97179371c9d4SSatish Balay     *OrthQualLabel = NULL;
97189371c9d4SSatish Balay   }
97199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
97209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
97219566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob));
97229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(glob, &ltog));
97239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH));
97249566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, OrthQual));
97259566063dSJacob Faibussowitsch   PetscCall(VecSetType(*OrthQual, VECSTANDARD));
97269566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE));
97279566063dSJacob Faibussowitsch   PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog));
97289566063dSJacob Faibussowitsch   PetscCall(VecSetUp(*OrthQual));
97299566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&glob));
97309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltog));
97319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL));
97329566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr));
97339566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(facegeom, &faceGeomArr));
97349566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
97359566063dSJacob Faibussowitsch   PetscCall(VecGetDM(facegeom, &dmFace));
97369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai));
97376ed19f2fSJacob Faibussowitsch   for (cell = cStart; cell < cEnd; cellIter++, cell++) {
97386ed19f2fSJacob Faibussowitsch     PetscInt         cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
9739f108dbd7SJacob Faibussowitsch     PetscInt         cellarr[2], *adj = NULL;
9740f108dbd7SJacob Faibussowitsch     PetscScalar     *cArr, *fArr;
9741898cd552SSatish Balay     PetscReal        minvalc = 1.0, minvalf = 1.0;
9742f108dbd7SJacob Faibussowitsch     PetscFVCellGeom *cg;
9743f108dbd7SJacob Faibussowitsch 
97446ed19f2fSJacob Faibussowitsch     idx[cellIter] = cell - cStart;
9745f108dbd7SJacob Faibussowitsch     cellarr[0]    = cell;
9746f108dbd7SJacob Faibussowitsch     /* Make indexing into cellGeom easier */
97479566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg));
97489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj));
9749f108dbd7SJacob Faibussowitsch     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
97509566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr));
97516ed19f2fSJacob Faibussowitsch     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) {
97526ed19f2fSJacob Faibussowitsch       PetscInt         i;
97536ed19f2fSJacob Faibussowitsch       const PetscInt   neigh  = adj[cellneigh];
9754f108dbd7SJacob Faibussowitsch       PetscReal        normci = 0, normfi = 0, normai = 0;
9755f108dbd7SJacob Faibussowitsch       PetscFVCellGeom *cgneigh;
9756f108dbd7SJacob Faibussowitsch       PetscFVFaceGeom *fg;
9757f108dbd7SJacob Faibussowitsch 
9758f108dbd7SJacob Faibussowitsch       /* Don't count ourselves in the neighbor list */
9759f108dbd7SJacob Faibussowitsch       if (neigh == cell) continue;
97609566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh));
9761f108dbd7SJacob Faibussowitsch       cellarr[1] = neigh;
97626ed19f2fSJacob Faibussowitsch       {
97636ed19f2fSJacob Faibussowitsch         PetscInt        numcovpts;
97646ed19f2fSJacob Faibussowitsch         const PetscInt *covpts;
97656ed19f2fSJacob Faibussowitsch 
97669566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts));
97679566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg));
97689566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts));
97696ed19f2fSJacob Faibussowitsch       }
9770f108dbd7SJacob Faibussowitsch 
9771f108dbd7SJacob Faibussowitsch       /* Compute c_i, f_i and their norms */
9772f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9773f108dbd7SJacob Faibussowitsch         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9774f108dbd7SJacob Faibussowitsch         fi[i] = fg->centroid[i] - cg->centroid[i];
9775f108dbd7SJacob Faibussowitsch         Ai[i] = fg->normal[i];
9776addd1e01SJunchao Zhang         normci += PetscPowReal(ci[i], 2);
9777addd1e01SJunchao Zhang         normfi += PetscPowReal(fi[i], 2);
9778addd1e01SJunchao Zhang         normai += PetscPowReal(Ai[i], 2);
9779f108dbd7SJacob Faibussowitsch       }
9780addd1e01SJunchao Zhang       normci = PetscSqrtReal(normci);
9781addd1e01SJunchao Zhang       normfi = PetscSqrtReal(normfi);
9782addd1e01SJunchao Zhang       normai = PetscSqrtReal(normai);
9783f108dbd7SJacob Faibussowitsch 
9784f108dbd7SJacob Faibussowitsch       /* Normalize and compute for each face-cell-normal pair */
9785f108dbd7SJacob Faibussowitsch       for (i = 0; i < nc; i++) {
9786f108dbd7SJacob Faibussowitsch         ci[i] = ci[i] / normci;
9787f108dbd7SJacob Faibussowitsch         fi[i] = fi[i] / normfi;
9788f108dbd7SJacob Faibussowitsch         Ai[i] = Ai[i] / normai;
9789f108dbd7SJacob Faibussowitsch         /* PetscAbs because I don't know if normals are guaranteed to point out */
9790f108dbd7SJacob Faibussowitsch         cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]);
9791f108dbd7SJacob Faibussowitsch         fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]);
9792f108dbd7SJacob Faibussowitsch       }
9793ad540459SPierre Jolivet       if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]);
9794ad540459SPierre Jolivet       if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]);
9795f108dbd7SJacob Faibussowitsch     }
97969566063dSJacob Faibussowitsch     PetscCall(PetscFree(adj));
97979566063dSJacob Faibussowitsch     PetscCall(PetscFree2(cArr, fArr));
9798f108dbd7SJacob Faibussowitsch     /* Defer to cell if they're equal */
97996ed19f2fSJacob Faibussowitsch     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9800f108dbd7SJacob Faibussowitsch     if (OrthQualLabel) {
98019566063dSJacob Faibussowitsch       if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE));
9802f108dbd7SJacob Faibussowitsch     }
9803f108dbd7SJacob Faibussowitsch   }
98049566063dSJacob Faibussowitsch   PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES));
98059566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(*OrthQual));
98069566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(*OrthQual));
98079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr));
98089566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr));
98099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL));
9810f108dbd7SJacob Faibussowitsch   if (OrthQualLabel) {
98119566063dSJacob Faibussowitsch     if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr));
9812f108dbd7SJacob Faibussowitsch   }
98139566063dSJacob Faibussowitsch   PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai));
9814cd791dc2SBarry Smith   PetscCall(PetscOptionsRestoreViewer(&vwr));
98159566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view"));
98163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9817f108dbd7SJacob Faibussowitsch }
9818f108dbd7SJacob Faibussowitsch 
9819d5b43468SJose E. Roman /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect
98201eb70e55SToby Isaac  * interpolator construction */
9821d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9822d71ae5a4SJacob Faibussowitsch {
98231eb70e55SToby Isaac   PetscSection section, newSection, gsection;
98241eb70e55SToby Isaac   PetscSF      sf;
98251eb70e55SToby Isaac   PetscBool    hasConstraints, ghasConstraints;
98261eb70e55SToby Isaac 
98271eb70e55SToby Isaac   PetscFunctionBegin;
98281eb70e55SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
98294f572ea9SToby Isaac   PetscAssertPointer(odm, 2);
98309566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
98319566063dSJacob Faibussowitsch   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
9832712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
98331eb70e55SToby Isaac   if (!ghasConstraints) {
98349566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
98351eb70e55SToby Isaac     *odm = dm;
98363ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
98371eb70e55SToby Isaac   }
98389566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, odm));
98399566063dSJacob Faibussowitsch   PetscCall(DMCopyFields(dm, *odm));
98409566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(*odm, &newSection));
98419566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(*odm, &sf));
98429566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
98439566063dSJacob Faibussowitsch   PetscCall(DMSetGlobalSection(*odm, gsection));
98449566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&gsection));
98453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98461eb70e55SToby Isaac }
98471eb70e55SToby Isaac 
9848d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9849d71ae5a4SJacob Faibussowitsch {
98501eb70e55SToby Isaac   DM        dmco, dmfo;
98511eb70e55SToby Isaac   Mat       interpo;
98521eb70e55SToby Isaac   Vec       rscale;
98531eb70e55SToby Isaac   Vec       cglobalo, clocal;
98541eb70e55SToby Isaac   Vec       fglobal, fglobalo, flocal;
98551eb70e55SToby Isaac   PetscBool regular;
98561eb70e55SToby Isaac 
98571eb70e55SToby Isaac   PetscFunctionBegin;
98589566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmc, &dmco));
98599566063dSJacob Faibussowitsch   PetscCall(DMGetFullDM(dmf, &dmfo));
98609566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dmfo, dmco));
98619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmf, &regular));
98629566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(dmfo, regular));
98639566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale));
98649566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmco, &cglobalo));
98659566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmc, &clocal));
98669566063dSJacob Faibussowitsch   PetscCall(VecSet(cglobalo, 0.));
98679566063dSJacob Faibussowitsch   PetscCall(VecSet(clocal, 0.));
98689566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmf, &fglobal));
98699566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmfo, &fglobalo));
98709566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmf, &flocal));
98719566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobal, 0.));
98729566063dSJacob Faibussowitsch   PetscCall(VecSet(fglobalo, 0.));
98739566063dSJacob Faibussowitsch   PetscCall(VecSet(flocal, 0.));
98749566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL));
98759566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo));
98769566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo));
98779566063dSJacob Faibussowitsch   PetscCall(MatMult(interpo, cglobalo, fglobalo));
98789566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal));
98799566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal));
98809566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal));
98819566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal));
98821eb70e55SToby Isaac   *shift = fglobal;
98839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&flocal));
98849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&fglobalo));
98859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&clocal));
98869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobalo));
98879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rscale));
98889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interpo));
98899566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfo));
98909566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmco));
98913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98921eb70e55SToby Isaac }
98931eb70e55SToby Isaac 
9894d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9895d71ae5a4SJacob Faibussowitsch {
98961eb70e55SToby Isaac   PetscObject shifto;
98971eb70e55SToby Isaac   Vec         shift;
98981eb70e55SToby Isaac 
98991eb70e55SToby Isaac   PetscFunctionBegin;
99001eb70e55SToby Isaac   if (!interp) {
99011eb70e55SToby Isaac     Vec rscale;
99021eb70e55SToby Isaac 
99039566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale));
99049566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rscale));
99051eb70e55SToby Isaac   } else {
99069566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)interp));
99071eb70e55SToby Isaac   }
99089566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto));
99091eb70e55SToby Isaac   if (!shifto) {
99109566063dSJacob Faibussowitsch     PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift));
99119566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift));
99121eb70e55SToby Isaac     shifto = (PetscObject)shift;
99139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shift));
99141eb70e55SToby Isaac   }
99151eb70e55SToby Isaac   shift = (Vec)shifto;
99169566063dSJacob Faibussowitsch   PetscCall(MatInterpolate(interp, coarseSol, fineSol));
99179566063dSJacob Faibussowitsch   PetscCall(VecAXPY(fineSol, 1.0, shift));
99189566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&interp));
99193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
99201eb70e55SToby Isaac }
99211eb70e55SToby Isaac 
9922bceba477SMatthew G. Knepley /* Pointwise interpolation
9923bceba477SMatthew G. Knepley      Just code FEM for now
9924bceba477SMatthew G. Knepley      u^f = I u^c
99254ca5e9f5SMatthew G. Knepley      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
99264ca5e9f5SMatthew G. Knepley      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
99274ca5e9f5SMatthew G. Knepley      I_{ij} = psi^f_i phi^c_j
9928bceba477SMatthew G. Knepley */
9929d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9930d71ae5a4SJacob Faibussowitsch {
9931bceba477SMatthew G. Knepley   PetscSection gsc, gsf;
9932bceba477SMatthew G. Knepley   PetscInt     m, n;
9933a063dac3SMatthew G. Knepley   void        *ctx;
993468132eb9SMatthew G. Knepley   DM           cdm;
9935cf51de39SMatthew G. Knepley   PetscBool    regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9936bceba477SMatthew G. Knepley 
9937bceba477SMatthew G. Knepley   PetscFunctionBegin;
99389566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
99399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
99409566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
99419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
994268132eb9SMatthew G. Knepley 
99439566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis));
99449566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation));
99459566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
99469566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype));
99479566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
994868132eb9SMatthew G. Knepley 
99499566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
99509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
99519566063dSJacob Faibussowitsch   if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx));
99529566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx));
99539566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
99544db47ee9SStefano Zampini   if (scaling) {
99555d1c2e58SMatthew G. Knepley     /* Use naive scaling */
99569566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
99574db47ee9SStefano Zampini   }
99583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9959a063dac3SMatthew G. Knepley }
9960bceba477SMatthew G. Knepley 
9961d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9962d71ae5a4SJacob Faibussowitsch {
99636dbf9973SLawrence Mitchell   VecScatter ctx;
996490748bafSMatthew G. Knepley 
9965a063dac3SMatthew G. Knepley   PetscFunctionBegin;
99669566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL));
99679566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat));
99689566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&ctx));
99693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9970bceba477SMatthew G. Knepley }
9971bceba477SMatthew G. Knepley 
9972d71ae5a4SJacob 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[])
9973d71ae5a4SJacob Faibussowitsch {
997400635df3SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
997500635df3SMatthew G. Knepley   PetscInt       c;
997600635df3SMatthew G. Knepley   for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
99773e9753d6SMatthew G. Knepley }
99783e9753d6SMatthew G. Knepley 
9979d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9980d71ae5a4SJacob Faibussowitsch {
9981b4937a87SMatthew G. Knepley   DM           dmc;
9982b4937a87SMatthew G. Knepley   PetscDS      ds;
9983b4937a87SMatthew G. Knepley   Vec          ones, locmass;
9984b4937a87SMatthew G. Knepley   IS           cellIS;
9985b4937a87SMatthew G. Knepley   PetscFormKey key;
9986b4937a87SMatthew G. Knepley   PetscInt     depth;
9987b4937a87SMatthew G. Knepley 
9988b4937a87SMatthew G. Knepley   PetscFunctionBegin;
99899566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmc));
99909566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, dmc));
99919566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &ds));
99929566063dSJacob Faibussowitsch   PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
99939566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dmc, mass));
99949566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &ones));
99959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmc, &locmass));
99969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmc, &depth));
99979566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
99989566063dSJacob Faibussowitsch   PetscCall(VecSet(locmass, 0.0));
99999566063dSJacob Faibussowitsch   PetscCall(VecSet(ones, 1.0));
10000b4937a87SMatthew G. Knepley   key.label = NULL;
10001b4937a87SMatthew G. Knepley   key.value = 0;
10002b4937a87SMatthew G. Knepley   key.field = 0;
10003b4937a87SMatthew G. Knepley   key.part  = 0;
100049566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL));
100059566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
100069566063dSJacob Faibussowitsch   PetscCall(VecSet(*mass, 0.0));
100079566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass));
100089566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass));
100099566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &ones));
100109566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmc, &locmass));
100119566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
100123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10013b4937a87SMatthew G. Knepley }
10014b4937a87SMatthew G. Knepley 
10015d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
10016d71ae5a4SJacob Faibussowitsch {
10017bd041c0cSMatthew G. Knepley   PetscSection gsc, gsf;
10018bd041c0cSMatthew G. Knepley   PetscInt     m, n;
10019bd041c0cSMatthew G. Knepley   void        *ctx;
10020bd041c0cSMatthew G. Knepley   DM           cdm;
10021bd041c0cSMatthew G. Knepley   PetscBool    regular;
10022bd041c0cSMatthew G. Knepley 
10023bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
100243e9753d6SMatthew G. Knepley   if (dmFine == dmCoarse) {
100253e9753d6SMatthew G. Knepley     DM            dmc;
100263e9753d6SMatthew G. Knepley     PetscDS       ds;
10027b4937a87SMatthew G. Knepley     PetscWeakForm wf;
100283e9753d6SMatthew G. Knepley     Vec           u;
100293e9753d6SMatthew G. Knepley     IS            cellIS;
1003006ad1575SMatthew G. Knepley     PetscFormKey  key;
100313e9753d6SMatthew G. Knepley     PetscInt      depth;
100323e9753d6SMatthew G. Knepley 
100339566063dSJacob Faibussowitsch     PetscCall(DMClone(dmFine, &dmc));
100349566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dmFine, dmc));
100359566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmc, &ds));
100369566063dSJacob Faibussowitsch     PetscCall(PetscDSGetWeakForm(ds, &wf));
100379566063dSJacob Faibussowitsch     PetscCall(PetscWeakFormClear(wf));
100389566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL));
100399566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dmc, mass));
100408d94ca23SJed Brown     PetscCall(DMGetLocalVector(dmc, &u));
100419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dmc, &depth));
100429566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS));
100439566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*mass));
100446528b96dSMatthew G. Knepley     key.label = NULL;
100456528b96dSMatthew G. Knepley     key.value = 0;
100466528b96dSMatthew G. Knepley     key.field = 0;
1004706ad1575SMatthew G. Knepley     key.part  = 0;
100489566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL));
100499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
100508d94ca23SJed Brown     PetscCall(DMRestoreLocalVector(dmc, &u));
100519566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmc));
100523e9753d6SMatthew G. Knepley   } else {
100539566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmFine, &gsf));
100549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
100559566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
100569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
10057bd041c0cSMatthew G. Knepley 
100589566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
100599566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
100609566063dSJacob Faibussowitsch     PetscCall(MatSetType(*mass, dmCoarse->mattype));
100619566063dSJacob Faibussowitsch     PetscCall(DMGetApplicationContext(dmFine, &ctx));
10062bd041c0cSMatthew G. Knepley 
100639566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dmFine, &cdm));
100649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetRegularRefinement(dmFine, &regular));
100659566063dSJacob Faibussowitsch     if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx));
100669566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx));
100673e9753d6SMatthew G. Knepley   }
100689566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
100693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10070bd041c0cSMatthew G. Knepley }
10071bd041c0cSMatthew G. Knepley 
100720aef6b92SMatthew G. Knepley /*@
100730aef6b92SMatthew G. Knepley   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
100740aef6b92SMatthew G. Knepley 
100750aef6b92SMatthew G. Knepley   Input Parameter:
10076a1cb98faSBarry Smith . dm - The `DMPLEX` object
100770aef6b92SMatthew G. Knepley 
100780aef6b92SMatthew G. Knepley   Output Parameter:
100790aef6b92SMatthew G. Knepley . regular - The flag
100800aef6b92SMatthew G. Knepley 
100810aef6b92SMatthew G. Knepley   Level: intermediate
100820aef6b92SMatthew G. Knepley 
100831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()`
100840aef6b92SMatthew G. Knepley @*/
10085d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
10086d71ae5a4SJacob Faibussowitsch {
100870aef6b92SMatthew G. Knepley   PetscFunctionBegin;
100880aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100894f572ea9SToby Isaac   PetscAssertPointer(regular, 2);
100900aef6b92SMatthew G. Knepley   *regular = ((DM_Plex *)dm->data)->regularRefinement;
100913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100920aef6b92SMatthew G. Knepley }
100930aef6b92SMatthew G. Knepley 
100940aef6b92SMatthew G. Knepley /*@
100950aef6b92SMatthew G. Knepley   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
100960aef6b92SMatthew G. Knepley 
100970aef6b92SMatthew G. Knepley   Input Parameters:
10098a1cb98faSBarry Smith + dm      - The `DMPLEX` object
100990aef6b92SMatthew G. Knepley - regular - The flag
101000aef6b92SMatthew G. Knepley 
101010aef6b92SMatthew G. Knepley   Level: intermediate
101020aef6b92SMatthew G. Knepley 
101031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()`
101040aef6b92SMatthew G. Knepley @*/
10105d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
10106d71ae5a4SJacob Faibussowitsch {
101070aef6b92SMatthew G. Knepley   PetscFunctionBegin;
101080aef6b92SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
101090aef6b92SMatthew G. Knepley   ((DM_Plex *)dm->data)->regularRefinement = regular;
101103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
101110aef6b92SMatthew G. Knepley }
101120aef6b92SMatthew G. Knepley 
10113a68b90caSToby Isaac /*@
10114f7c74593SToby Isaac   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
10115a1cb98faSBarry Smith   call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`.
10116a68b90caSToby Isaac 
10117a1cb98faSBarry Smith   Not Collective
10118a68b90caSToby Isaac 
10119f899ff85SJose E. Roman   Input Parameter:
10120a1cb98faSBarry Smith . dm - The `DMPLEX` object
10121a68b90caSToby Isaac 
10122a68b90caSToby Isaac   Output Parameters:
1012320f4b53cSBarry Smith + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points.
1012420f4b53cSBarry Smith - anchorIS      - If not `NULL`, set to the list of anchors indexed by `anchorSection`
10125a68b90caSToby Isaac 
10126a68b90caSToby Isaac   Level: intermediate
10127a68b90caSToby Isaac 
101281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection`
10129a68b90caSToby Isaac @*/
10130d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
10131d71ae5a4SJacob Faibussowitsch {
10132a68b90caSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
10133a68b90caSToby Isaac 
10134a68b90caSToby Isaac   PetscFunctionBegin;
10135a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
101369566063dSJacob Faibussowitsch   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm));
10137a68b90caSToby Isaac   if (anchorSection) *anchorSection = plex->anchorSection;
10138a68b90caSToby Isaac   if (anchorIS) *anchorIS = plex->anchorIS;
101393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10140a68b90caSToby Isaac }
10141a68b90caSToby Isaac 
10142a68b90caSToby Isaac /*@
10143a4e35b19SJacob Faibussowitsch   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.
10144a68b90caSToby Isaac 
1014520f4b53cSBarry Smith   Collective
10146a68b90caSToby Isaac 
10147a68b90caSToby Isaac   Input Parameters:
10148a1cb98faSBarry Smith + dm            - The `DMPLEX` object
10149a1cb98faSBarry Smith . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.
10150a1cb98faSBarry Smith                   Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10151a1cb98faSBarry Smith - anchorIS      - The list of all anchor points.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
10152a68b90caSToby Isaac 
10153a68b90caSToby Isaac   Level: intermediate
10154a68b90caSToby Isaac 
10155a1cb98faSBarry Smith   Notes:
10156a4e35b19SJacob Faibussowitsch   Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to
10157a4e35b19SJacob Faibussowitsch   an outside value, the anchor constraints set a point's degrees of freedom to be a linear
10158a4e35b19SJacob Faibussowitsch   combination of other points' degrees of freedom.
10159a4e35b19SJacob Faibussowitsch 
10160a1cb98faSBarry Smith   After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling
10161a1cb98faSBarry Smith   `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix.
10162a1cb98faSBarry Smith 
1016320f4b53cSBarry Smith   The reference counts of `anchorSection` and `anchorIS` are incremented.
10164a1cb98faSBarry Smith 
101651cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`
10166a68b90caSToby Isaac @*/
10167d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
10168d71ae5a4SJacob Faibussowitsch {
10169a68b90caSToby Isaac   DM_Plex    *plex = (DM_Plex *)dm->data;
10170e228b242SToby Isaac   PetscMPIInt result;
10171a68b90caSToby Isaac 
10172a68b90caSToby Isaac   PetscFunctionBegin;
10173a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10174e228b242SToby Isaac   if (anchorSection) {
10175e228b242SToby Isaac     PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2);
101769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result));
101771dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator");
10178e228b242SToby Isaac   }
10179e228b242SToby Isaac   if (anchorIS) {
10180e228b242SToby Isaac     PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3);
101819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result));
101821dca8a05SBarry Smith     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator");
10183e228b242SToby Isaac   }
10184a68b90caSToby Isaac 
101859566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorSection));
101869566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&plex->anchorSection));
10187a68b90caSToby Isaac   plex->anchorSection = anchorSection;
10188a68b90caSToby Isaac 
101899566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)anchorIS));
101909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&plex->anchorIS));
10191a68b90caSToby Isaac   plex->anchorIS = anchorIS;
10192a68b90caSToby Isaac 
10193cf9c20a2SJed Brown   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
10194a68b90caSToby Isaac     PetscInt        size, a, pStart, pEnd;
10195a68b90caSToby Isaac     const PetscInt *anchors;
10196a68b90caSToby Isaac 
101979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
101989566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(anchorIS, &size));
101999566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(anchorIS, &anchors));
10200a68b90caSToby Isaac     for (a = 0; a < size; a++) {
10201a68b90caSToby Isaac       PetscInt p;
10202a68b90caSToby Isaac 
10203a68b90caSToby Isaac       p = anchors[a];
10204a68b90caSToby Isaac       if (p >= pStart && p < pEnd) {
10205a68b90caSToby Isaac         PetscInt dof;
10206a68b90caSToby Isaac 
102079566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10208a68b90caSToby Isaac         if (dof) {
102099566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(anchorIS, &anchors));
1021063a3b9bcSJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p);
10211a68b90caSToby Isaac         }
10212a68b90caSToby Isaac       }
10213a68b90caSToby Isaac     }
102149566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(anchorIS, &anchors));
10215a68b90caSToby Isaac   }
10216f7c74593SToby Isaac   /* reset the generic constraints */
102179566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL));
102183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10219a68b90caSToby Isaac }
10220a68b90caSToby Isaac 
10221d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
10222d71ae5a4SJacob Faibussowitsch {
10223f7c74593SToby Isaac   PetscSection anchorSection;
102246995de1eSToby Isaac   PetscInt     pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
10225a68b90caSToby Isaac 
10226a68b90caSToby Isaac   PetscFunctionBegin;
10227a68b90caSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
102299566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec));
102309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
102316995de1eSToby Isaac   if (numFields) {
10232719ab38cSToby Isaac     PetscInt f;
102339566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(*cSec, numFields));
10234719ab38cSToby Isaac 
10235719ab38cSToby Isaac     for (f = 0; f < numFields; f++) {
10236719ab38cSToby Isaac       PetscInt numComp;
10237719ab38cSToby Isaac 
102389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
102399566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp));
10240719ab38cSToby Isaac     }
102416995de1eSToby Isaac   }
102429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd));
102439566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
102446995de1eSToby Isaac   pStart = PetscMax(pStart, sStart);
102456995de1eSToby Isaac   pEnd   = PetscMin(pEnd, sEnd);
102466995de1eSToby Isaac   pEnd   = PetscMax(pStart, pEnd);
102479566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd));
10248a68b90caSToby Isaac   for (p = pStart; p < pEnd; p++) {
102499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(anchorSection, p, &dof));
10250a68b90caSToby Isaac     if (dof) {
102519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
102529566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(*cSec, p, dof));
10253a68b90caSToby Isaac       for (f = 0; f < numFields; f++) {
102549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
102559566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof));
10256a68b90caSToby Isaac       }
10257a68b90caSToby Isaac     }
10258a68b90caSToby Isaac   }
102599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(*cSec));
102609566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section"));
102613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10262a68b90caSToby Isaac }
10263a68b90caSToby Isaac 
10264d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
10265d71ae5a4SJacob Faibussowitsch {
10266f7c74593SToby Isaac   PetscSection    aSec;
10267ae65431dSMatthew G. Knepley   PetscInt        pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
102680ac89760SToby Isaac   const PetscInt *anchors;
102690ac89760SToby Isaac   PetscInt        numFields, f;
1027066ad2231SToby Isaac   IS              aIS;
10271e19f7ee6SMark Adams   MatType         mtype;
10272e19f7ee6SMark Adams   PetscBool       iscuda, iskokkos;
102730ac89760SToby Isaac 
102740ac89760SToby Isaac   PetscFunctionBegin;
102750ac89760SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
102769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cSec, &m));
102779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &n));
102789566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, cMat));
102799566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*cMat, m, n, m, n));
102809566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda));
102819566063dSJacob Faibussowitsch   if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda));
102829566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos));
102839566063dSJacob Faibussowitsch   if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos));
10284e19f7ee6SMark Adams   if (iscuda) mtype = MATSEQAIJCUSPARSE;
10285e19f7ee6SMark Adams   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
10286e19f7ee6SMark Adams   else mtype = MATSEQAIJ;
102879566063dSJacob Faibussowitsch   PetscCall(MatSetType(*cMat, mtype));
102889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
102899566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
102906995de1eSToby Isaac   /* cSec will be a subset of aSec and section */
102919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
102929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &sStart, &sEnd));
102939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m + 1, &i));
102940ac89760SToby Isaac   i[0] = 0;
102959566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
102960ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
10297f19733c5SToby Isaac     PetscInt rDof, rOff, r;
10298f19733c5SToby Isaac 
102999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(aSec, p, &rDof));
10300f19733c5SToby Isaac     if (!rDof) continue;
103019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
103020ac89760SToby Isaac     if (numFields) {
103030ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
103040ac89760SToby Isaac         annz = 0;
10305f19733c5SToby Isaac         for (r = 0; r < rDof; r++) {
10306f19733c5SToby Isaac           a = anchors[rOff + r];
10307ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
103089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
103090ac89760SToby Isaac           annz += aDof;
103100ac89760SToby Isaac         }
103119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
103129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off));
10313ad540459SPierre Jolivet         for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
103140ac89760SToby Isaac       }
103152f7452b8SBarry Smith     } else {
103160ac89760SToby Isaac       annz = 0;
103179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
103180ac89760SToby Isaac       for (q = 0; q < dof; q++) {
10319ae65431dSMatthew G. Knepley         a = anchors[rOff + q];
10320ae65431dSMatthew G. Knepley         if (a < sStart || a >= sEnd) continue;
103219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(section, a, &aDof));
103220ac89760SToby Isaac         annz += aDof;
103230ac89760SToby Isaac       }
103249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
103259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSec, p, &off));
10326ad540459SPierre Jolivet       for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz;
103270ac89760SToby Isaac     }
103280ac89760SToby Isaac   }
103290ac89760SToby Isaac   nnz = i[m];
103309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &j));
103310ac89760SToby Isaac   offset = 0;
103320ac89760SToby Isaac   for (p = pStart; p < pEnd; p++) {
103330ac89760SToby Isaac     if (numFields) {
103340ac89760SToby Isaac       for (f = 0; f < numFields; f++) {
103359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof));
103360ac89760SToby Isaac         for (q = 0; q < dof; q++) {
103370ac89760SToby Isaac           PetscInt rDof, rOff, r;
103389566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(aSec, p, &rDof));
103399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
103400ac89760SToby Isaac           for (r = 0; r < rDof; r++) {
103410ac89760SToby Isaac             PetscInt s;
103420ac89760SToby Isaac 
103430ac89760SToby Isaac             a = anchors[rOff + r];
10344ae65431dSMatthew G. Knepley             if (a < sStart || a >= sEnd) continue;
103459566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof));
103469566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff));
10347ad540459SPierre Jolivet             for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
103480ac89760SToby Isaac           }
103490ac89760SToby Isaac         }
103500ac89760SToby Isaac       }
103512f7452b8SBarry Smith     } else {
103529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec, p, &dof));
103530ac89760SToby Isaac       for (q = 0; q < dof; q++) {
103540ac89760SToby Isaac         PetscInt rDof, rOff, r;
103559566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &rDof));
103569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &rOff));
103570ac89760SToby Isaac         for (r = 0; r < rDof; r++) {
103580ac89760SToby Isaac           PetscInt s;
103590ac89760SToby Isaac 
103600ac89760SToby Isaac           a = anchors[rOff + r];
10361ae65431dSMatthew G. Knepley           if (a < sStart || a >= sEnd) continue;
103629566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
103639566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
10364ad540459SPierre Jolivet           for (s = 0; s < aDof; s++) j[offset++] = aOff + s;
103650ac89760SToby Isaac         }
103660ac89760SToby Isaac       }
103670ac89760SToby Isaac     }
103680ac89760SToby Isaac   }
103699566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL));
103709566063dSJacob Faibussowitsch   PetscCall(PetscFree(i));
103719566063dSJacob Faibussowitsch   PetscCall(PetscFree(j));
103729566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
103733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103740ac89760SToby Isaac }
103750ac89760SToby Isaac 
10376d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
10377d71ae5a4SJacob Faibussowitsch {
10378f7c74593SToby Isaac   DM_Plex     *plex = (DM_Plex *)dm->data;
10379f7c74593SToby Isaac   PetscSection anchorSection, section, cSec;
1038066ad2231SToby Isaac   Mat          cMat;
1038166ad2231SToby Isaac 
1038266ad2231SToby Isaac   PetscFunctionBegin;
1038366ad2231SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
103849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL));
1038566ad2231SToby Isaac   if (anchorSection) {
1038644a7f3ddSMatthew G. Knepley     PetscInt Nf;
10387e228b242SToby Isaac 
103889566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dm, &section));
103899566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec));
103909566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat));
103919566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
103929566063dSJacob Faibussowitsch     if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat));
103939566063dSJacob Faibussowitsch     PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL));
103949566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&cSec));
103959566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&cMat));
1039666ad2231SToby Isaac   }
103973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1039866ad2231SToby Isaac }
10399a93c429eSMatthew G. Knepley 
10400d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
10401d71ae5a4SJacob Faibussowitsch {
10402a93c429eSMatthew G. Knepley   IS           subis;
10403a93c429eSMatthew G. Knepley   PetscSection section, subsection;
10404a93c429eSMatthew G. Knepley 
10405a93c429eSMatthew G. Knepley   PetscFunctionBegin;
104069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1040728b400f6SJacob Faibussowitsch   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
1040828b400f6SJacob Faibussowitsch   PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
10409a93c429eSMatthew G. Knepley   /* Create subdomain */
104109566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dm, label, value, subdm));
10411a93c429eSMatthew G. Knepley   /* Create submodel */
104129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSubpointIS(*subdm, &subis));
104139566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection));
104149566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*subdm, subsection));
104159566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&subsection));
104169566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *subdm));
10417a93c429eSMatthew G. Knepley   /* Create map from submodel to global model */
10418a93c429eSMatthew G. Knepley   if (is) {
10419a93c429eSMatthew G. Knepley     PetscSection    sectionGlobal, subsectionGlobal;
10420a93c429eSMatthew G. Knepley     IS              spIS;
10421a93c429eSMatthew G. Knepley     const PetscInt *spmap;
10422a93c429eSMatthew G. Knepley     PetscInt       *subIndices;
10423a93c429eSMatthew G. Knepley     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
10424a93c429eSMatthew G. Knepley     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
10425a93c429eSMatthew G. Knepley 
104269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSubpointIS(*subdm, &spIS));
104279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(spIS, &spmap));
104289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
104299566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
104309566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal));
104319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd));
10432a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10433a93c429eSMatthew G. Knepley       PetscInt gdof, pSubSize = 0;
10434a93c429eSMatthew G. Knepley 
104359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
10436a93c429eSMatthew G. Knepley       if (gdof > 0) {
10437a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10438a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof;
10439a93c429eSMatthew G. Knepley 
104409566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof));
104419566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof));
10442a93c429eSMatthew G. Knepley           pSubSize += fdof - fcdof;
10443a93c429eSMatthew G. Knepley         }
10444a93c429eSMatthew G. Knepley         subSize += pSubSize;
10445a93c429eSMatthew G. Knepley         if (pSubSize) {
10446a93c429eSMatthew G. Knepley           if (bs < 0) {
10447a93c429eSMatthew G. Knepley             bs = pSubSize;
10448a93c429eSMatthew G. Knepley           } else if (bs != pSubSize) {
10449a93c429eSMatthew G. Knepley             /* Layout does not admit a pointwise block size */
10450a93c429eSMatthew G. Knepley             bs = 1;
10451a93c429eSMatthew G. Knepley           }
10452a93c429eSMatthew G. Knepley         }
10453a93c429eSMatthew G. Knepley       }
10454a93c429eSMatthew G. Knepley     }
10455a93c429eSMatthew G. Knepley     /* Must have same blocksize on all procs (some might have no points) */
104569371c9d4SSatish Balay     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
104579371c9d4SSatish Balay     bsLocal[1] = bs;
104589566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
104599371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
104609371c9d4SSatish Balay       bs = 1;
104619371c9d4SSatish Balay     } else {
104629371c9d4SSatish Balay       bs = bsMinMax[0];
104639371c9d4SSatish Balay     }
104649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
10465a93c429eSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
10466a93c429eSMatthew G. Knepley       PetscInt gdof, goff;
10467a93c429eSMatthew G. Knepley 
104689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof));
10469a93c429eSMatthew G. Knepley       if (gdof > 0) {
10470a93c429eSMatthew G. Knepley         const PetscInt point = spmap[p];
10471a93c429eSMatthew G. Knepley 
104729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff));
10473a93c429eSMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
10474a93c429eSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
10475a93c429eSMatthew G. Knepley 
10476a93c429eSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
10477a93c429eSMatthew G. Knepley           for (f2 = 0; f2 < f; ++f2) {
104789566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
104799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
10480a93c429eSMatthew G. Knepley             poff += fdof - fcdof;
10481a93c429eSMatthew G. Knepley           }
104829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
104839566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
10484ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
10485a93c429eSMatthew G. Knepley         }
10486a93c429eSMatthew G. Knepley       }
10487a93c429eSMatthew G. Knepley     }
104889566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(spIS, &spmap));
104899566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
10490a93c429eSMatthew G. Knepley     if (bs > 1) {
10491a93c429eSMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
10492a93c429eSMatthew G. Knepley       PetscInt i, j, set = 1;
10493a93c429eSMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
10494a93c429eSMatthew G. Knepley         for (j = 0; j < bs; ++j) {
104959371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
104969371c9d4SSatish Balay             set = 0;
104979371c9d4SSatish Balay             break;
104989371c9d4SSatish Balay           }
10499a93c429eSMatthew G. Knepley         }
10500a93c429eSMatthew G. Knepley       }
105019566063dSJacob Faibussowitsch       if (set) PetscCall(ISSetBlockSize(*is, bs));
10502a93c429eSMatthew G. Knepley     }
10503a93c429eSMatthew G. Knepley     /* Attach nullspace */
10504a93c429eSMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
10505a93c429eSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
10506a93c429eSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) break;
10507a93c429eSMatthew G. Knepley     }
10508a93c429eSMatthew G. Knepley     if (f < Nf) {
10509a93c429eSMatthew G. Knepley       MatNullSpace nullSpace;
105109566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace));
105116823f3c5SBlaise Bourdin 
105129566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
105139566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
10514a93c429eSMatthew G. Knepley     }
10515a93c429eSMatthew G. Knepley   }
105163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10517a93c429eSMatthew G. Knepley }
10518c0f0dcc3SMatthew G. Knepley 
10519c0f0dcc3SMatthew G. Knepley /*@
10520c0f0dcc3SMatthew G. Knepley   DMPlexMonitorThroughput - Report the cell throughput of FE integration
10521c0f0dcc3SMatthew G. Knepley 
10522a1cb98faSBarry Smith   Input Parameters:
10523a1cb98faSBarry Smith + dm    - The `DM`
10524a1cb98faSBarry Smith - dummy - unused argument
10525a1cb98faSBarry Smith 
10526a1cb98faSBarry Smith   Options Database Key:
10527a1cb98faSBarry Smith . -dm_plex_monitor_throughput - Activate the monitor
10528c0f0dcc3SMatthew G. Knepley 
10529c0f0dcc3SMatthew G. Knepley   Level: developer
10530c0f0dcc3SMatthew G. Knepley 
105311cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()`
10532c0f0dcc3SMatthew G. Knepley @*/
10533d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
10534d71ae5a4SJacob Faibussowitsch {
10535b665b14eSToby Isaac   PetscLogHandler default_handler;
10536b665b14eSToby Isaac 
105372611ad71SToby Isaac   PetscFunctionBegin;
105382611ad71SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10539b665b14eSToby Isaac   PetscCall(PetscLogGetDefaultHandler(&default_handler));
10540b665b14eSToby Isaac   if (default_handler) {
10541c0f0dcc3SMatthew G. Knepley     PetscLogEvent      event;
10542c0f0dcc3SMatthew G. Knepley     PetscEventPerfInfo eventInfo;
10543c0f0dcc3SMatthew G. Knepley     PetscReal          cellRate, flopRate;
10544c0f0dcc3SMatthew G. Knepley     PetscInt           cStart, cEnd, Nf, N;
10545c0f0dcc3SMatthew G. Knepley     const char        *name;
10546c0f0dcc3SMatthew G. Knepley 
105479566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
105489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
105499566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(dm, &Nf));
105509566063dSJacob Faibussowitsch     PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event));
10551b665b14eSToby Isaac     PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo));
10552c0f0dcc3SMatthew G. Knepley     N        = (cEnd - cStart) * Nf * eventInfo.count;
10553c0f0dcc3SMatthew G. Knepley     flopRate = eventInfo.flops / eventInfo.time;
10554c0f0dcc3SMatthew G. Knepley     cellRate = N / eventInfo.time;
1055563a3b9bcSJacob 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)));
105562611ad71SToby Isaac   } else {
10557b665b14eSToby 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.");
105582611ad71SToby Isaac   }
105593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10560c0f0dcc3SMatthew G. Knepley }
10561